我试图构建一个类型安全的附件系统,但是当泛型函数调用中的类型不匹配时,打字稿似乎不会抛出错误
// 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");
我不明白为什么当密钥和值的类型不对齐时,最后一行不会抛出编译器错误。
编辑:根据jcalz评论,我理解为什么会这样。但是,有没有办法保持类型安全呢?答案 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