如何使TypeScript类型保护对编译产生影响?
我创建了一个名为如何使TypeScript类型保护对编译产生影响?,typescript,types,Typescript,Types,我创建了一个名为KVMap的类,该类继承自Map,但类型完全不同 class KVMap<T extends object> extends Map<keyof T, T[keyof T]> { ... 所有类型都可以选择未定义,您可以在键上调用。清除或。删除 到目前为止一切正常 Map的原始类型有一个问题:调用.has意味着您仍然可能得到编译器错误。 例如: 这是因为.has只返回一个布尔值。 我试图解决这个问题 我在继承的类中重新定义了。has,如下所示:
KVMap
的类,该类继承自Map
,但类型完全不同
class KVMap<T extends object> extends Map<keyof T, T[keyof T]> {
...
所有类型都可以选择未定义
,您可以在键上调用。清除
或。删除
到目前为止一切正常
Map
的原始类型有一个问题:调用.has
意味着您仍然可能得到编译器错误。
例如:
这是因为.has
只返回一个布尔值。
我试图解决这个问题
我在继承的类中重新定义了。has
,如下所示:
has<K extends keyof T>(key: K): this is this & {
get(key: K): T[K]
};
has(key:K):这是这个&{
get(key:K):T[K]
};
这意味着以后调用.get
将不再在其类型中包含| undefined
然而,我认为this
的原始类型,因为它包含可选的未定义类型,优先于类型guard union
有人知道我该怎么解决这个问题吗
(如果有必要,我可以附加更多的代码)手册文档中没有明确说明,但是当您创建两个可调用类型的类型时,它生成的类型就像带有两个调用签名的类型,其顺序与它们在交叉点中出现的顺序相同。因此,虽然直观上和在TypeScript中它们通常是,但函数类型的交集不是:
ns.foo()
因此,您的类型guardthis是这个&{get(key:K):T[K]}
的问题在于原始的this
有一个get()
类型为Map[“get”]
的方法,因此生成的交集只是在那之后添加了一个新的重载方法。由于原始的get()
方法适用于所有keyof T
输入,因此它将始终处于选中状态,因此您添加的重载方法将完全隐藏:
interface Tee {
a: string,
b: number,
c: boolean
}
const v = new KVMap<Tee>();
if (v.has("a")) {
v.get; /* OVERLOADED:
get(key: "a" | "b" | "c"): string | number | boolean | undefined;
get(key: "a"): string
*/
v.get("a").toUpperCase(); // error!
万岁
但请注意,只有将单个字符串文本类型的值传递给has()
时,这种类型保护才有意义。如果has()
的参数是联合类型,那么您将度过一段不愉快的时光,尽管编译器向开发人员保证这是不可能的,但在运行时仍然可能会出现未定义的
:
// problem
const bc = Math.random() < 0.5 ? "b" : "c";
const cb = (bc === "b") ? "c" : "b";
if (v.has(bc)) {
v.get(cb).toString(); // compiles fine, but error at runtime!
}
//问题
常量bc=Math.random()<0.5?“b”:“c”;
常数cb=(bc=“b”)?“c”:“b”;
如果(v.has(bc)){
v、 get(cb).toString();//编译很好,但在运行时出错!
}
所以要小心
你在说什么“断言”?我没有看到任何类型断言here@jcalz您是对的,更新为使用“Type-Guard”代替断言;我忘了它的名字。我快死了,TS是一种有趣的语言。从什么时候开始,秩序在其他语言中起作用了!?交换订单,效果很好。谢谢你指出这一点。
type FN = {foo(): number};
type FS = {foo(): string};
declare const ns: FN & FS;
ns.foo().toFixed(); // okay
ns.foo().toUpperCase(); // error
declare const sn: FS & FN;
sn.foo().toFixed(); // error
sn.foo().toUpperCase(); // okay
interface Tee {
a: string,
b: number,
c: boolean
}
const v = new KVMap<Tee>();
if (v.has("a")) {
v.get; /* OVERLOADED:
get(key: "a" | "b" | "c"): string | number | boolean | undefined;
get(key: "a"): string
*/
v.get("a").toUpperCase(); // error!
class KVMap<T extends object> extends Map<keyof T, T[keyof T]> {
declare readonly has: <K extends keyof T>(key: K) => this is {
get(key: K): T[K]
} & this;
}
const v = new KVMap<Tee>();
if (v.has("a")) {
v.get("a").toUpperCase(); // okay now
}
// problem
const bc = Math.random() < 0.5 ? "b" : "c";
const cb = (bc === "b") ? "c" : "b";
if (v.has(bc)) {
v.get(cb).toString(); // compiles fine, but error at runtime!
}