1. Typescript的结构类型系统是什么?

    Anders Hejlsberg先后设计了C#和Typescript, 两者有很多相似之处,但是其本质区别是
    C#采用的 标明类型系统
    TS 采用的是结构类型系统

  1. public class Foo
  2. {
  3. public string Name { get; set; }
  4. public int Id { get; set;}
  5. }
  6. public class Bar
  7. {
  8. public string Name { get; set; }
  9. public int Id { get;set }
  10. }
  11. Foo foo = new Foo(); // Okay
  12. Bar bar = new Foo(); // Error!!!

即使Foo和Bar两个类的内部定义完全一致,但是赋值是会报错,可见两者类型本质是不同的

  1. class Foo {
  2. method(input: string):number {}
  3. }
  4. class Bar {
  5. method(input: string):number {}
  6. }
  7. const foo:Foo = new Foo() // Okay
  8. const bar:Bar = new Foo() // Okay

TS只要两者类型相同,即可以赋值,本质原因是TS比较的并不是类型定义本身,而是类型定义的形状
TS采用结构类型系统,是为了兼容js灵活的特性

  1. 如何防止两种类型在结构上兼容

由于TS采用了灵活的结构类型系统,那么会导致一些问题

  1. interface ScreenCoordinate {
  2. x: number;
  3. y: number;
  4. }
  5. interface PrintCoordinate {
  6. x: number;
  7. y: number;
  8. }
  9. function sendToPrinter(pt: PrintCoordinate) {
  10. // .....
  11. }
  12. function getCursorPos(): ScreenCoordinate {
  13. return { x:0, y:0 }
  14. }
  15. sendToPrinter(getCursorPos())

由于ScreenCoordinate和PrintCoordinate的形状是相同的,那么根据结构类型系统的特性,它们的类型是兼容的,
但是如果不想让他们是兼容的类型如何操作?
添加一个[brand]成员:

  1. interface ScreenCoordinate {
  2. _screenCoordBrand: any;
  3. x: number;
  4. y: number;
  5. }
  6. interface PrintCoordinate {
  7. _printCoordBrand: any;
  8. x: number;
  9. y: number;
  10. }
  11. // 报错
  12. sendToPrinter(getCursorPos());
  1. TS类型的substitutability?
    1. function handler(arg: string) {
    2. //...
    3. }
    4. function doSomething(callback: (arg1: string, arg2: number) => void) {
    5. callback('hello', 42)
    6. }
    7. doSomething(handler)
    8. // 一般预期这里会报错,因为doSomething要求的回调函数式有两个参数的,
    9. // 但是handlerz只有一个参数
    TS支持更少的参数的函数可以赋值给更多的参数的函数, 究其原因是因为handler类型 (arg: string)=> xxx 是可以作为(arg1: string, arg2: number) => void 的替代品,在这种情况下是不会报错的
    类似的例子还有 ```typescript function doSomething(): number { return 42 } function callMeMaybe(callback: () => void) { callback() }

// 一般认为这里会报错,原因是doSomething返回的是number, 而callback返回的是void; callMeMayBe(doSomething) ``` TS有substitutability的设计,原因也是要兼容JS的灵活性

小结

  1. TS的类型系统,是结构型类型系统,即结构相同则认为类型相同
  2. TS防止两种类型在结构上兼容,可以通过给结构相同的接口添加 [band ]成员解决
  3. TS的substituability的设计,参数更少的函数可以赋值给参数更多的函数,即使类型不相同