简体   繁体   English

打字稿对通用类型不匹配没有错误

[英]Typescript no error on generic type mismatch

I'm attempting to build a type safe attachment system, but typescript doesn't seem to throw an error when the types mismatch in a generic function call 我正在尝试构建类型安全的附件系统,但是当泛型函数调用中的类型不匹配时,打字稿似乎没有引发错误

// 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 TS游乐场链接

I don't see why the last line doesn't throw a compiler error when the type of the key and value don't line up. 我不明白为什么当键和值的类型不对齐时最后一行不会引发编译器错误。

EDIT: per jcalz comment, I understand why this is the case. 编辑:每个jcalz评论,我理解为什么是这种情况。 However, is there a way around this that maintains type safety? 但是,有没有一种方法可以保持类型安全?

The reason is that your generic type GenericTypeMarker doesn't use the type parameter T . 原因是您的通用类型GenericTypeMarker不使用类型参数T As of TypeScript 2.8, the compiler can flag that as an error . 从TypeScript 2.8开始,编译器可以将其标记为error

What you want is called literal types in Flow. 您想要的是Flow中的文字类型 There have been requests to add it to TypeScript. 有人要求将其添加到TypeScript。

As others have mentioned if you don't use the type parameter it has little effect on compatibility, so the simplest solution is to use it. 正如其他人提到的,如果您不使用type参数,则对兼容性几乎没有影响,因此最简单的解决方案是使用它。 The most benign way to use it is to intersect string with a type that contains a dummy property, (similar to branded types) 使用它的最佳方法是将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

The disadvantage is someone might try to access TestKey.marker and be surprised that there is no value. 缺点是有人可能尝试访问TestKey.marker并惊讶于没有任何价值。 One workaround is to use T & never for the marker type which although when you try to access marker evaluates to never still works for the purpose of infering T in putItems for example: 一个解决办法是使用T & nevermarker这虽然当您尝试访问类型marker计算为never仍然可以工作,infering的目的TputItems例如:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM