microsoft / microsoft/TypeScript

New intrinsic for Hashing a type to a string

未关闭
#62,363 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

Awaiting More Feedback Suggestion
主要语言
Go
星标
111k
派生
14.3k
平均合并
2 天 4 小时
30 天内合并 PR
132

描述

🔍 Search Terms

Intrinsic hash type

✅ Viability Checklist
⭐ 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:

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:

const ItalianTranslation = {
    piano: "Pianoforte",
    guitar: "Chitarra",
    electricGuitar: "Chitarra elettrica",
} satisfies Record<InstrumentName, string>

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:

const ItalianTranslation = {
    piano: "Pianoforte",
    guitar: "Chitarra",
    electricGuitar: "Chitarra elettrica",
} satisfies Record<InstrumentName, string>

// Pretend I had already calculated the hash of the instrument
// object when I first implemented ItalianTranslation.
// And the hash back then was "dhgb123a"
IsEqual<HashOf<Instruments>, "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

贡献指南

打开贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

调研方向

该 issue 没有指定任何文件、测试或入口点。首先应根据 TypeScript 的类型系统设计目标和所述用例,评估提议的 HashOf intrinsic;只有确定了设计,并制定了计算和比较类型哈希的实现计划,才算完成。

由索引模型根据 Issue 内容生成。

评估

技术栈
typescript
领域
compilers
Issue 类型
功能
难度
5/5
预计耗时
一周以上
活跃度
停滞
描述清晰度
基本清楚
新手友好度
30/100

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。