Appearance
接口
接口(Interfaces)来定义对象的类型。
- 一般首字母大写
- 赋值时,变量须和接口保持一致
js
interface Person {
name: string;
age: number;
}
let tom: Person = {
name: 'Tom'
}
// index.ts(6,5): error TS2322: Type '{ name: string; }' is not assignable to type 'Person'.
// Property 'age' is missing in type '{ name: string; }'接口可以定义多次,并自动合并
tsx
interface Point {
x: number
}
interface Point {
y: number
}
const point: Point = { x: 1, y: 2 }可选 | 只读属性
可选属性:属性选填
只读属性:只能在创建时修改值
tsx
interface Person {
readonly name: string
age?: number
}ts 提供的ReadonlyArray<T> 类型,它将可变方法去掉,保证数组创建后不能再修改
tsx
let a: number[] = [1, 2, 3, 4]
let ro: ReadonlyArray<number> = a
ro[0] = 12 // error!
ro.push(5) // error!
ro.length = 100 // error!
a = ro // error!任意属性
用索引签名来表示任意属性
- 一个接口只能定义一个任意属性
tsx
interface Person {
name: string
age?: number
[propName: string]: any
}
let tom: Person = {
name: 'Tom',
gender: 'male'
}定义了任意属性,确定属性和可选属性的类型都必须是它的类型的子集
tsx
interface Person {
name: string
age?: number // 这里真实的类型应该为:number | undefined
[propName: string]: string | number | undefined // 这样声明才不报错
}绕开属性检测
鸭式辨别法
鸭式辨型法:像鸭子一样走路并且嘎嘎叫的就叫鸭子,即具有鸭子特征的认为它就是鸭子。
通过制定规则来判定对象是否实现这个接口。
tsx
interface LabeledValue {
label: string
}
function printLabel(labeledObj: LabeledValue) {
console.log(labeledObj.label)
}
printLabel({ size: 10, label: 'Size 10 Object' }) // Error报错原因:参数接收对象,相当于直接赋值,有严格定义,不能多参或少参。
解决方法:通过外部变量传参
tsx
interface LabeledValue {
label: string
}
function printLabel(labeledObj: LabeledValue) {
console.log(labeledObj.label)
}
let myObj = { size: 10, label: 'Size 10 Object' }
printLabel(myObj) // OK分析:myObj 不会经过额外属性检查,但会被推断为 {size: number, label: string},此时相当于两种类型赋值,参照鸭式辨别法,两种类型都具有 label 属性,所以认定为相同。
类型断言
类型断言:手动指定类型,ts 不会进行额外检测
tsx
// * as Props
interface Props {
name: string
age: number
money?: number
}
let p: Props = {
name: '兔神',
age: 25,
money: -100000,
girl: false
} as Props // OK索引签名
通过索引签名定义任意属性接收值
tsx
// [key: string]: any;
interface Props {
name: string
age: number
money?: number
[key: string]: any
}
let p: Props = {
name: '兔神',
age: 25,
money: -100000,
girl: false
} // OK接口与类型别名区别
接口:定义数据模型
别名:给类型取个新名字
大多数情况下等效
对象和函数
两者都可以用来描述对象或函数的类型,但是语法不同
tsx
interface Point {
x: number
y: number
}
interface SetPoint {
(x: number, y: number): void
}tsx
type Point = {
x: number
y: number
}
type SetPoint = (x: number, y: number) => void其他类型
与接口不同,类型别名还能作用于其他类型(原始类型、联合类型、元组)
tsx
// primitive
type Name = string
// object
type PartialPointX = { x: number }
type PartialPointY = { y: number }
// union
type PartialPoint = PartialPointX | PartialPointY
// tuple
type Data = [number, string]
// dom
let div = document.createElement('div')
type B = typeof div接口可以定义多次,自动合并为单个接口。类型别名不行
js
interface Point {
x: number;
}
interface Point {
y: number;
}
const point: Point = { x: 1, y: 2 }扩展
interface:继承方式扩展(extends)
type:交叉类型方式扩展(&)
tsx
interface PointX {
x: number
}
interface Point extends PointX {
y: number
}tsx
type PointX = {
x: number
}
type Point = PointX & {
y: number
}interface 和 type 之间也可以互相扩展
接口扩展类型别名
tsx
type PointX = {
x: number
}
interface Point extends PointX {
y: number
}类型别名扩展接口
tsx
interface PointX {
x: number
}
type Point = PointX & {
y: number
}