这是 DeepReadonly 的一个实现(取自这里,这是这个挑战的解决方案)。
type DeepReadonly<T> = keyof T extends never
? T
: { readonly [k in keyof T]: DeepReadonly<T[k]> };
Run Code Online (Sandbox Code Playgroud)
这里的目的是什么extends never?我认为它是递归类型的某种基本情况,但我不明白我们什么时候会遇到它,以及为什么它首先是必要的(因为打字稿显然确实允许一些其他类型的自引用类型定义,而无需这种基本情况)例)。
jca*_*alz 23
我想我和你有同样的问题。简短的回答是,我认为这不是一个很好的实现DeepReadonly<T>,对于编写它的人来说并没有冒犯的意思。
Sokeyof T extends never意味着该类型没有已知的键T,因为该keyof运算符生成已知键的并集,并且该never类型是 TypeScript 的底层类型,这是一种根本没有值的类型。这意味着keyof T extends never行为如下:
type Hmm<T> = keyof T extends never ? true : false
type X1 = Hmm<{ a: string }> // false, "a" is a known key
type X2 = Hmm<{}> // true, there are no known keys
type X3 = Hmm<object> // true, there are no known keys
type X4 = Hmm<string> // false, there are keys like "toUpperCase"
type X5 = Hmm<
{ a: string } | { b: string }
> // true, unions with no common keys have no known keys
Run Code Online (Sandbox Code Playgroud)
现在,这并不是一个很好的实现方法DeepReadonly<T>,假设您只是想在遇到原始类型时停止递归。但考虑到上面的输出,事实并非如此keyof T extends never。例如:
type DeepReadonly<T> = keyof T extends never
? T
: { readonly [K in keyof T]: DeepReadonly<T[K]> };
type Z = DeepReadonly<{ a: string } | { b: string }>
// type Z = {a: string} | {b: string} OOPS
declare const z: Z;
if ("a" in z) {
z.a = "" // no error, not readonly
}
Run Code Online (Sandbox Code Playgroud)
由于我们传递了一个联合,编译器将其键视为never,突然间我们什么地方都没有了readonly。哎呀。
“正确”的定义DeepReadonly<T>可能就是
type DeepReadonly<T> =
{ readonly [K in keyof T]: DeepReadonly<T[K]> };
Run Code Online (Sandbox Code Playgroud)
映射类型已经通过返回输入“跳过”基元,并且它们自动分布在联合上,因此您不需要自己检查这些:
type Look<T> = { [K in keyof T]: 123 };
type Y1 = Look<{ a: string }> // {a: 123}
type Y2 = Look<string> // string
type Y3 = Look<{ a: string } | { b: string }>
// Look<{ a: string; }> | Look<{ b: string; }>
Run Code Online (Sandbox Code Playgroud)
因此,通过这个版本,DeepReadonly我们也获得了工会的正确行为:
type Z = DeepReadonly<{ a: string } | { b: string }>
// type Z = DeepReadonly<{ a: string; }> | DeepReadonly<{ b: string; }>
declare const z: Z;
if ("a" in z) {
z.a = "" // error! Cannot assign to 'a' because it is a read-only property
}
Run Code Online (Sandbox Code Playgroud)
type DeepReadonly<T> = T extends object ?
{ readonly [K in keyof T]: DeepReadonly<T[K]> } : T;
Run Code Online (Sandbox Code Playgroud)
这与没有检查的类型类似:T extends object ? ... : T是一种分布式条件类型,因此它会自动拆分联合,处理它们,然后将它们重新组合在一起:
type Z = DeepReadonly<{ a: string } | { b: string }>
// type Z = { readonly a: string; } | { readonly b: string; }
Run Code Online (Sandbox Code Playgroud)
尽管 IntelliSense 的快速信息以不同的方式显示它们,但这与之前的类型相同。
| 归档时间: |
|
| 查看次数: |
7709 次 |
| 最近记录: |