北龙建设集团网站,网站网页转小程序教程,商城火车站,改wordpress评论邮箱要完全理解类型推论需要完整理解类型上下文#xff0c;并且理解TS对于是否可以使用类型推论是基于静态分析完成的。 上下文类型应用在许多地方。常见的例子包括函数调用的参数#xff0c;赋值的右手端位置#xff0c;类型断言#xff0c;对象和数组的成员#xff0c;和返回…要完全理解类型推论需要完整理解类型上下文并且理解TS对于是否可以使用类型推论是基于静态分析完成的。 上下文类型应用在许多地方。常见的例子包括函数调用的参数赋值的右手端位置类型断言对象和数组的成员和返回语句。上下文类型还充当最佳公共类型中的候选类型。 TS中需要为每个JS名字规定类型而名字出现在对应的上下文中则会自动获得类型若没有对应的上下文这个名字则会自动获得类型any。 名字通过声明语句声明的名字例如var、let、const、function a() {}、class A {}、import A from ‘.a’、函数参数等都会在JS环境中添加一个名字而TS可以给这个名字指定类型。 在JS中名字的声明是可以在上面提到的常见例子指定的位置函数参数调用、赋值右手端位置、对象数组成员、返回语句。
函数调用的参数
interface Cb {(a: number): void;
}
interface Fn {(cb: Cb): void;
}const fn: Fn function (cb) {}fn(function (a) { // 这里a的类型是numberconsole.log(a 1)
})因为fn这个名字是类型Fn而Fn类型的入参是类型Cb所以在fn使用匿名函数作为入参调用的时候TS可以知道这个匿名函数对应的位置是类型Cb换句话说匿名函数当前的类型上下文是Cb。而Cb要求入参是number类型所以推断出匿名函数的参数a是number类型。
赋值的右手端位置
interface Cb {(a: number): void;
}const fn: Cb function (a) {console.log(a 1)
}fn是类型Cb因为Cb要求入参是number类型所以TS推断出对应位置匿名函数的入参是number类型。
对象和数组的成员
interface Cb {(a: number): void;
}
interface Obj {fn: Cb
}
const obj: Obj {fn: function (a) {console.log(a 1)}
}obj是类型Obj而Obj具有属性fn是类型Cb。因为Cb要求入参是number类型所以TS推断出对象obj.fn右手端对应位置匿名函数的入参是number类型。
返回语句
interface Cb {(a: number): void
}interface Fn {(): Cb
}const fn: Fn function () {return (a) {console.log(a 1)}
}在这例子里返回的匿名函数获得类型上下文Cb而Cb要求入参是number所以匿名函数的入参被推断出是number类型。
上面的几种类型都可以认为名字出现在了赋值的右手端而被复制的名字可以给这个值提供对应的类型上下文。
类型断言
interface Fn {(a: number): void;
}const fn function (a) {console.log(a 1);
} as Fn;在这里匿名函数赋值给变量fn而fn本身是没有类型的所以没办法推断匿名函数的入参a的类型但是我们使用类型给这个匿名函数指定了类型上下文Fn让TS具有了推算参数a的依据得出参数a是number类型。
小结
类型推断起作用的条件是名字出现在对应的上下文位置而这个上下文可以通过赋值操作的左手端提供也可以使用类型断言直接提供。这样TS可以根据对应的类型推断出对应变量的类型。
一些意外
interface Fn {(a: number): void;
}function fn(a) {}let a: Fn fn在这个例子里TS无法推断出函数fn的参数a是number类型因为赋值操作提供的类型上下文在右手端而fn这个函数声明的位置并不是右手端。对应的右手端位置并不是函数声明而是函数声明的引用。所以TS无法静态分析出fn中a的类型。 还有一个原因是fn的使用并不唯一在这里我们将fn赋值给Fn类型的变量a我们完全可以将它再赋值给Fn1类型的变量b所以这种情况下fn中a的类型是由运行时决定的无法静态分析出来。
interface Fn {(a: number): void;
}function fn(a) {}let a: Fn fninterface Fn1 {(a: number): void;
}let b: Fn1 fn这里Fn1要求入参a的类型是string所以fn的入参a既可能是number也可能是string只有运行这个函数的时候才能确定知道参数a是什么类型。所以在这个例子中a会自动获得隐式类型any。
进行如下修改
interface Fn {(a: number): void;
}let a: Fn function fn(a) {}在这里fn是一个表达式并不会再当前环境中新建一个名字fn换句话说这个fn不会再用在别的地方并且a这个名字直接出现在了右手端对应位置所以这个fn函数可以得到类型上下文Fn从而推断出参数a的类型是number。