Typescript的结构类型系统是什么?
Anders Hejlsberg先后设计了C#和Typescript, 两者有很多相似之处,但是其本质区别是
C#采用的 标明类型系统
TS 采用的是结构类型系统
public class Foo{public string Name { get; set; }public int Id { get; set;}}public class Bar{public string Name { get; set; }public int Id { get;set }}Foo foo = new Foo(); // OkayBar bar = new Foo(); // Error!!!
即使Foo和Bar两个类的内部定义完全一致,但是赋值是会报错,可见两者类型本质是不同的
class Foo {method(input: string):number {}}class Bar {method(input: string):number {}}const foo:Foo = new Foo() // Okayconst bar:Bar = new Foo() // Okay
TS只要两者类型相同,即可以赋值,本质原因是TS比较的并不是类型定义本身,而是类型定义的形状
TS采用结构类型系统,是为了兼容js灵活的特性
- 如何防止两种类型在结构上兼容
由于TS采用了灵活的结构类型系统,那么会导致一些问题
interface ScreenCoordinate {x: number;y: number;}interface PrintCoordinate {x: number;y: number;}function sendToPrinter(pt: PrintCoordinate) {// .....}function getCursorPos(): ScreenCoordinate {return { x:0, y:0 }}sendToPrinter(getCursorPos())
由于ScreenCoordinate和PrintCoordinate的形状是相同的,那么根据结构类型系统的特性,它们的类型是兼容的,
但是如果不想让他们是兼容的类型如何操作?
添加一个[brand]成员:
interface ScreenCoordinate {_screenCoordBrand: any;x: number;y: number;}interface PrintCoordinate {_printCoordBrand: any;x: number;y: number;}// 报错sendToPrinter(getCursorPos());
- TS类型的substitutability?
TS支持更少的参数的函数可以赋值给更多的参数的函数, 究其原因是因为handler类型 (arg: string)=> xxx 是可以作为(arg1: string, arg2: number) => void 的替代品,在这种情况下是不会报错的function handler(arg: string) {//...}function doSomething(callback: (arg1: string, arg2: number) => void) {callback('hello', 42)}doSomething(handler)// 一般预期这里会报错,因为doSomething要求的回调函数式有两个参数的,// 但是handlerz只有一个参数
类似的例子还有 ```typescript function doSomething(): number { return 42 } function callMeMaybe(callback: () => void) { callback() }
// 一般认为这里会报错,原因是doSomething返回的是number, 而callback返回的是void; callMeMayBe(doSomething) ``` TS有substitutability的设计,原因也是要兼容JS的灵活性
小结
- TS的类型系统,是结构型类型系统,即结构相同则认为类型相同
- TS防止两种类型在结构上兼容,可以通过给结构相同的接口添加 [band ]成员解决
- TS的substituability的设计,参数更少的函数可以赋值给参数更多的函数,即使类型不相同
