W4G*_*4G1 23 typescript typescript-generics
运行以下代码片段时出现错误Object is possibly 'undefined'. ts(2532)。
const myMap = new Map<string, number>();
myMap.set('test', 1);
// Object is possibly 'undefined'.
myMap.get('test') / 2;
Run Code Online (Sandbox Code Playgroud)
我正在使用 TypeScript 4.5.4(也在 4.4.4 上检查过)
如果这是有意的,有人可以解释一下上面的例子怎么可能仍然是未定义的吗?
jca*_*alz 39
这在某种程度上是 TypeScript 的设计限制;编译器无法跟踪Map这种方式的状态。microsoft/TypeScript#9619有一个(相当旧的)功能请求来支持方法的控制流分析Map。
但是,如果不改变语言就无法做到这一点。目前Map<K, V>被声明为interface. 该set()方法的返回类型为this(因为调用set()返回相同的Map实例)。该get()方法的返回类型为V | undefined。
但实际上并没有一种方法可以说改变实例的set() 状态get(),以便使用“正确”的键将返回而V不是V | undefined。从某种意义上说,您希望调用将frommyMap.set("test", 1)的类型(它不知道哪些键具有实际值)更改为类似 的类型。想必您希望将类型更改为. 但 TypeScript 不允许您表示这样的任意类型突变。有断言方法,但有很多警告,其中最大的警告是它们仅严格缩小类型,如果编译器没有将行为视为缩小,则它将无法工作。myMapMap<string, number>Map<string, number> & {get("test"): number}myMap.delete("test")Map<string, number> & {get("test"): undefined}
所以现在这基本上是一个限制。这并不意味着myMap.get('test')实际上可以undefined,只是编译器不知道这一点。
您可能想要解决它或重构,而不是等待 TypeScript 的某些未来版本支持此用例。最简单的解决方法是接受您比编译器更聪明的事实,并使用非空断言告诉它一个值不能是nullor undefined:
const myMap = new Map<string, number>();
myMap.set("test", 1);
myMap.get("test")! / 2; // <-- no error
Run Code Online (Sandbox Code Playgroud)
如果你确实需要编译器跟踪这些事情,那么你可以重构以使用方法链;您不再使用myMap每次调用时状态都不同的单个对象set(),而是使用多个对象,每个对象都有一个常量状态……当您调用时,set()您会得到一个新对象。它可能看起来像这样:
const init = new MyMap();
//const init: MyMap<{}>
const afterSet = init.set("test", 1);
//const afterSet: MyMap<Record<"test", number>>
const val = afterSet.get("test") / 2;
Run Code Online (Sandbox Code Playgroud)
或者像这样:
const m = new MyMap().set("test", 1).set("foo", "abc").set("baz", false);
m.get("foo").toUpperCase();
m.get("test").toFixed();
m.get("blah") // error! not a valid key
Run Code Online (Sandbox Code Playgroud)
这是一种可能的实现(仅处理get()andset()但您也可以实现其他方法):
interface MyMap<T extends object = {}> {
set<K extends keyof T>(k: K, v: T[K]): this;
set<K extends string, V>(k: Exclude<K, keyof T>, v: V): MyMap<T & Record<K, V>>;
get<K extends string>(k: K): K extends keyof T ? T[K] : undefined;
}
const MyMap = Map as new () => MyMap;
Run Code Online (Sandbox Code Playgroud)
小智 8
Typescript 不会跟踪引用.set .get,并且默认签名是.get,T | undefined因此您可以:
myMap.get('test')!之间的代码可能会更改/删除该项目).set.getconst myMap = new Map<string, number>();
myMap.set('test', 1);
// Object is possibly 'undefined'.
const item = myMap.get('test');
if (item !== undefined) {
item / 2;
} else {
throw new Error('Item is undefined');
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
20975 次 |
| 最近记录: |