簡體   English   中英

TypeScript 如何處理這樣的映射類型?

[英]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 Tnever ,則整個映射類型將被丟棄並返回T

我發現功能resolveMappedTypeMemberschecker.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

在以下函數上放置一個斷點,然后將鼠標懸停在A1type A1 = DeepReadonly<number> )。 逐步執行代碼。

在此處輸入圖片說明

我無法引用 TypeScript 源代碼給您答案,但常見問題解答中提到了這種情況:

此映射類型返回原始類型,而不是對象類型。

聲明為{ [ K in keyof T ]: U }其中T是類型參數的映射類型被稱為同態映射類型,這意味着映射類型是T的結構保留函數。 當使用原始類型實例化類型參數T ,映射類型計算為相同的原始類型。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM