打字稿没有关于泛型类型不匹配的错误

时间:2018-04-03 19:35:37

标签: typescript generics

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

// 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评论,我理解为什么会这样。但是,有没有办法保持类型安全呢?

2 个答案:

答案 0 :(得分:1)

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

您想要的内容在Flow中称为literal types。已将requests添加到TypeScript。

答案 1 :(得分:1)

正如其他人提到的,如果你不使用type参数,它对兼容性几乎没有影响,所以最简单的解决方案就是使用它。使用它的最良性方法是将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 & never用于marker类型,但是当您尝试访问marker时,评估结果为never仍然可用于推断T in例如putItems

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