TypeScript 常见问题

奴止
Oct 25, 2022
Last edited: 2022-10-25
type
Post
status
Published
date
Oct 25, 2022
slug
typescript-fqa
summary
一些常见的 TypeScript 问题,方便你我他。
tags
TypeScript
前端开发
category
技术随手记
icon
password
Property
Oct 25, 2022 03:50 PM
🔥
持续更新中….
 
💡
本文中的代码可以复制粘贴到 TypeScript Playground 中自行体会。
 

几个关键点

 
  • TypeScript是结构化类型(结构相同那就是一样的类型)
  • 子类型可以赋值给父类型(animal = dog),反之不可
  • 属性多的是子类型,但是联合类型越多反而是父类型
  • 用是否安全来考虑类型是否兼容的问题
 

协变、逆变(啥玩意儿?)

忘记那些名词,以类型安全来考虑就行。
 

简单类型

  • 简单类型1
type Parent = { name: string } type Child = { name: string age: number } let p: Parent = { name: 'parent' } let c: Child = { name: 'child', age: 1 } p = c // ok c = p // error: Property 'age' is missing in type 'Parent' but required in type 'Child'
 
  • 简单类型2(联合类型)
type One = string type Two = string | number type Three = string | number | boolean let one:One = '' let two:Two = 2 let three:Three = false one = two // error,如你所见,two 可能会是 number,所以类型不安全 one = three // error,类似上理 two = one // ok two = three // error,类似上理 three = one // ok three = two // ok
 
  • 复合类型
如下,可以看到类型 Parent 之于 Child 与复合类型 Comp<Parent> 之于 Comp<Child> 具有一致性(所谓协变Covariance):
type Parent = { name: string } type Child = { name: string age: number } type Comp<T> = T[] let p: Parent = { name: 'parent' } let c: Child = { name: 'child', age: 1 } let cp: Comp<Parent> = [p] let cc: Comp<Child> = [c] p = c // ok c = p // error: missing 'age' cp = cc // ok cc = cp // error: Type 'Parent' is not assignable to type 'Child' cp = [c] // ok cc = [p] // error: Type 'Parent' is not assignable to type 'Child'
 
  • 函数
在函数中,(p: Parent)=>void 之于 (c: Child)=>void 却与 Parent 之于 Child 正好相反(所谓逆变Contravariant):
type B = (a: A | A[]) => void const b1: B = (a: A) => { } // error: Type 'string[]' is not assignable to type 'string' const b2: B = (a: A[]) => { } // error: Type 'string' is not assignable to type 'string[]' type Parent = { name: string } type Child = { name: string age: number } type FuncParent = (p: Parent) => void type FuncChild = (c: Child) => void let p: Parent = { name: 'parent' } let c: Child = { name: 'child', age: 1 } let fp: FuncParent = (p) => { } let fc: FuncChild = (c) => { } p = c // ok c = p // error: Property 'age' is missing in type 'Parent' but required in type 'Child' fp = fc // error: Type 'Parent' is not assignable to type 'Child' fc = fp // ok
从安全层面考虑:假设如果 fc 可以赋值给 fp,那么类型约束是按照 Parent 来的,但是实际调用时,却是使用的Child 来调用,此时如果假设 fc 里依赖 c.age,那肯定会有问题了(按 fp 来检查,无法保证 age 是存在的)。
 
⚠️
注意:仅在 tsconfig#strictFunctionTypes 开启时才会成立。

本节参考

  1. README - TypeScript Deep Dive (gitbook.io)
  1. 快速理解 TypeScript 的逆变、协变、双向协变、不变 - 知乎 (zhihu.com)
 
企业微信h5开发笔记TypeScript 小抄