microsoft / microsoft/TypeScript

New intrinsic for Hashing a type to a string

Ouverte
#62,363 0 commentaires 0 réactions 0 personnes assignées Voir sur GitHub

Personne n'a encore pris cette issue.

Awaiting More Feedback Suggestion
Langage dominant
Go
Étoiles
111k
Forks
14.3k
Merge moyen
2 j 4 h
PR mergées (30 j)
132

Description

### 🔍 Search Terms

Intrinsic hash type

### ✅ Viability Checklist

- [x] This wouldn't be a breaking change in existing TypeScript/JavaScript code
- [x] This wouldn't change the runtime behavior of existing JavaScript code
- [x] This could be implemented without emitting different JS based on the types of the expressions
- [x] This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
- [x] This isn't a request to add a new utility type: https://github.com/microsoft/TypeScript/wiki/No-New-Utility-Types
- [x] This feature would agree with the rest of our Design Goals: https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals

### ⭐ Suggestion

I'd like an intrinsic type, called something along the lines of `HashOf`, which computes a small hash string of a TypeScript type. Together with versioning and comparisons between the generated hash and a string literal type, it can be used as a "contract" between the developer and implementer that "guarantees" that the underlying assumptions of a type have not changed. This can make it easier for library authors to signal minor breaking changes that do not alter the type signature.

The way it is used is outside the scope of this proposal. The proposal is only for an intrinsic type, `HashOf` or a similar name, that, given a TypeScript type, returns a small string representing the hash of the type. As pseudocode, imagine `hash(JSON.stringify(myType))`. Currently, this cannot be implemented efficiently within the type system.

### 📃 Motivating Example

When working with TypeScript, I tend to rely heavily on type inference of `const` objects and extensive use of `satisfies` to "remind" me of changes I need to make whenever I update an object. I'll use the example of translations to explain further.

Often, I have an object like:

```ts
const instrument = {
piano: "Piano",
guitar: "Guitar",
electricGuitar: "Electric Guitar"
//...
} as const

type Instruments = typeof instrument
type InstrumentName = keyof Instruments
````

Then, somewhere else in the code, I might have a translation or a mapping from the `InstrumentName` key to some other constant:

```ts
const ItalianTranslation = {
piano: "Pianoforte",
guitar: "Chitarra",
electricGuitar: "Chitarra elettrica",
} satisfies Record
```

Here, I'm using `satisfies` to encode the "contract" between the instrument names and their Italian translations. So whenever I add a new instrument, I am reminded by a type error that I also need to translate it.

This works, but imagine a user complains about the name "Guitar" and requests a clearer name to avoid confusion with "Electric Guitar." I decide to rename `Guitar` to `Acoustic Guitar`. TypeScript does not remind me to change the translation because the key hasn't changed, only the value has. This is a minor breaking change that I would like to signal to the consumers of my code (in this case, myself). It doesn't break the type, but it changes the underlying assumptions.

If there were a `HashOf` intrinsic, I could first compute the hash of the type when I initially use it, save it in a literal, and later compare it with the hash of the type itself:

```ts
const ItalianTranslation = {
piano: "Pianoforte",
guitar: "Chitarra",
electricGuitar: "Chitarra elettrica",
} satisfies Record

// Pretend I had already calculated the hash of the instrument
// object when I first implemented ItalianTranslation.
// And the hash back then was "dhgb123a"
IsEqual, "dhgb123a">

// Or alternatively, I can make a utility type that combines IsEqual and HashOf
```

This way, whenever `Instruments` changes, I am reminded to update the translation implementation.

The example is relevant to any scenario that requires a "mapping" from one type to another, where we need to remember to change something when one type changes. Another example is saving information to a database. We might have a service that saves an object but only cares about a subset of its properties. If the original object is updated, we might want to include additional properties in the database. Without a mechanism like `HashOf`, we must manually remember to update all relevant mapping points.

### 💻 Use Cases

1. I'd mostly use this to handle prompt translations in LLMs, where I have one prompt in English and need to maintain the variants that are translated in other languages. Or when I have to save an object when using Prisma ORM, and the object has optional keys that I need to remind myself to add whenever I add a new optional key to the object. In short, wherever I map type A to type B.
2. It is currently hard to efficiently compute the hash of a type using typescript type system.
3. An alternative and what I'm doing now is something somewhat similar, aka doing the hash by hand by using versioning. I can create a new type which has only the versions of objects in it (or the version of one object) and then do the same comparison in the place I need to remind myself to modify

Guide de contribution

Ouvrir le guide de contribution

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Piste de recherche

L’issue ne nomme aucun fichier, test ou point d’entrée. Commencez par évaluer l’intrinsic HashOf proposé au regard des objectifs de conception du système de types de TypeScript et des cas d’utilisation indiqués ; le travail ne serait terminé qu’une fois le design arrêté et un plan d’implémentation établi pour calculer et comparer les hashes de types.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Évaluation

Stack technique
typescript
Domaine
compilers
Type d'issue
Fonctionnalité
Difficulté
5/5
Temps estimé
Plus d'une semaine
Activité
À l'abandon
Clarté
Plutôt claire
Accessibilité débutants
30/100

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.