【问题标题】:Typescript no error on generic type mismatch打字稿在泛型类型不匹配上没有错误
【发布时间】:2018-04-04 04:44:32
【问题描述】:

我正在尝试构建一个类型安全的附件系统,但是当泛型函数调用中的类型不匹配时,打字稿似乎不会引发错误

// Generic key that holds value type info
type GenericTypeMarker<T> = string;

// Standard dictionarny
const dictionary: { [id: string]: any } = {};

// Put item into dict with type specified by key
function putItem<T>(key: GenericTypeMarker<T>, item: T) {
    dictionary[key] = item;
}

// Get item from dict with type specified by key
function getItem<T>(key: GenericTypeMarker<T>): T {
    return dictionary[key];
}


// A test key with type of number
const TestKey: GenericTypeMarker<number> = "testKey";

// type mismatch between value and key, but no error
putItem(TestKey, "not a string");

TS Playground link

我不明白为什么当键和值的类型不对齐时最后一行不会引发编译器错误。

编辑:根据 jcalz 的评论,我理解为什么会这样。但是,有没有一种方法可以保持类型安全?

【问题讨论】:

标签: typescript generics


【解决方案1】:

原因是你的泛型类型GenericTypeMarker 没有使用类型参数T。从 TypeScript 2.8 开始,编译器可以将其标记为 an error

您想要的在 Flow 中称为 literal types。已经有requests 将其添加到 TypeScript 中。

【讨论】:

    【解决方案2】:

    正如其他人提到的,如果你不使用类型参数它对兼容性的影响很小,所以最简单的解决方案就是使用它。最温和的使用方式是将string 与包含虚拟属性的类型相交,(类似于品牌类型)

    // Generic key that holds value type info
    type GenericTypeMarker<T> = string & { markerHelper: T };
    
    // Standard dictionarny
    const dictionary: { [id: string]: any } = {};
    
    // Put item into dict with type specified by key
    function putItem<T>(key: GenericTypeMarker<T>, item: T) {
        dictionary[key] = item;
    }
    
    function makeMarker<T>(value : string) : GenericTypeMarker<T>{
      return value as any
    }
    // create the key with an any assertion 
    const TestKey: GenericTypeMarker<number> = "testKey" as any;
    // or using the helper
    const TestKey2 =  makeMarker<number>("testKey");
    
    putItem(TestKey,2); // ok
    putItem(TestKey,"2");// error
    

    缺点是有人可能会尝试访问 TestKey.marker 并惊讶于没有任何价值。一种解决方法是将T &amp; never 用于marker 类型,尽管当您尝试访问markerevaluates 到never 时仍然可以在putItems 中推断T,例如:

    type GenericTypeMarker<T> = string & { marker: T & never};
    
    const TestKey =  makeMarker<number>("testKey");
    let d = TestKey.marker; // d is never
    putItem(TestKey,2); // ok
    putItem(TestKey,"2");// error
    

    【讨论】:

    • @jcalz 我不敢相信又把它们搞混了,10x :)
    猜你喜欢
    • 2022-01-18
    • 2019-08-11
    • 2018-12-17
    • 2020-10-07
    • 2021-11-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多