[英]How TypeScript handle mapped type like this?
我正在編寫一個通用的DeepReadonly
類型:
type DeepReadonly<T> = {
readonly [P in keyof T]: true;
};
type A1 = DeepReadonly<number>;
type A2 = DeepReadonly<string>;
type A3 = DeepReadonly<boolean>;
type A4 = DeepReadonly<symbol>;
type A5 = DeepReadonly<never>;
type A6 = DeepReadonly<null>;
type A7 = DeepReadonly<undefined>;
type A8 = DeepReadonly<bigint>;
type A9 = DeepReadonly<void>;
type A10 = DeepReadonly<{a: string}>;
我發現A1~A9
是它自己的參數類型。 TypeScript 如何處理這種映射類型? 我的猜測:如果keyof T
是never
,則整個映射類型將被丟棄並返回T
。
我發現功能resolveMappedTypeMembers
在checker.ts
。 但確實找到了更多有用的信息。
有人可以用 TypeScript 源代碼解釋這一點嗎? 謝謝。
更新:
感謝投票答案的作者。 我在 TypeScript 源代碼中找到了函數instantiateMappedType
,其中對算法進行了很好的解釋:
function instantiateMappedType(type: MappedType, mapper: TypeMapper, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]): Type {
// For a homomorphic mapped type { [P in keyof T]: X }, where T is some type variable, the mapping
// operation depends on T as follows:
// * If T is a primitive type no mapping is performed and the result is simply T.
// * If T is a union type we distribute the mapped type over the union.
// * If T is an array we map to an array where the element type has been transformed.
// * If T is a tuple we map to a tuple where the element types have been transformed.
// * Otherwise we map to an object type where the type of each property has been transformed.
// For example, when T is instantiated to a union type A | B, we produce { [P in keyof A]: X } |
// { [P in keyof B]: X }, and when when T is instantiated to a union type A | undefined, we produce
// { [P in keyof A]: X } | undefined.
const typeVariable = getHomomorphicTypeVariable(type);
if (typeVariable) {
const mappedTypeVariable = instantiateType(typeVariable, mapper);
if (typeVariable !== mappedTypeVariable) {
return mapTypeWithAlias(getReducedType(mappedTypeVariable), t => {
if (t.flags & (TypeFlags.AnyOrUnknown | TypeFlags.InstantiableNonPrimitive | TypeFlags.Object | TypeFlags.Intersection) && t !== wildcardType && t !== errorType) {
if (!type.declaration.nameType) {
if (isArrayType(t)) {
return instantiateMappedArrayType(t, type, prependTypeMapping(typeVariable, t, mapper));
}
if (isGenericTupleType(t)) {
return instantiateMappedGenericTupleType(t, type, typeVariable, mapper);
}
if (isTupleType(t)) {
return instantiateMappedTupleType(t, type, prependTypeMapping(typeVariable, t, mapper));
}
}
return instantiateAnonymousType(type, prependTypeMapping(typeVariable, t, mapper));
}
return t;
}, aliasSymbol, aliasTypeArguments);
}
}
// If the constraint type of the instantiation is the wildcard type, return the wildcard type.
return instantiateType(getConstraintTypeFromMappedType(type), mapper) === wildcardType ? wildcardType : instantiateAnonymousType(type, mapper, aliasSymbol, aliasTypeArguments);
}
更新:
我設法構建了一個本地 TypeScript 並能夠調試 tsserver.js
在以下函數上放置一個斷點,然后將鼠標懸停在A1
( type A1 = DeepReadonly<number>
)。 逐步執行代碼。
我無法引用 TypeScript 源代碼給您答案,但常見問題解答中提到了這種情況:
此映射類型返回原始類型,而不是對象類型。
聲明為
{ [ K in keyof T ]: U }
其中T
是類型參數的映射類型被稱為同態映射類型,這意味着映射類型是T
的結構保留函數。 當使用原始類型實例化類型參數T
,映射類型計算為相同的原始類型。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.