Exploring TypeScript Type Annotations - Defining Types
关于
作者: zhilidali
欢迎来到 《探索 TypeScript 类型注解》 系列教程。
上一篇介绍了 TypeScript 的内置类型,本篇探索如何创建自定义类型。
目录
正文
1 接口
使用 interface
关键字。
interface MyType {}
对象结构
TS 基于结构类型 Structural Typing
基本语法 : K: T
描述对象的形状(结构)
// 定义属性 a 为字符串类型,属性 b 为数值类型
interface MyType {
a: string;
b: number;
}
// 使用自定义的 MyType 类型
let bar: MyType = { a: 'ts', b: 1 };
let baz: MyType = { a: 1000, b: 1 }; // Error
let foo: MyType = { a: 'ts' }; // Error (结构不一致)
可选属性 : K?: T
interface MyType {
a: string;
b?: number
}
let foo: MyType = { a: 'ts' };
只读属性 : readonly K: T
interface MyType {
a: string;
readonly b: number;
}
let bar: MyType = { a: 'ts', b: 1 };
bar.a = 'TypeScript';
bar.b = 2; // Error
索引签名
索引签名 Index Signature
- 字符串索引签名 String Index Signature
- 数值索引签名 Number Index Signature
字符串索引签名 :[K: string]: T
描述任意属性
interface MyType {
a: string;
[k: string]: string;
}
let baz: MyType = { a: 'ts', b: 'foo' };
数值索引签名 :[K: number]: T
描述数组类型
interface MyType {
[index: number]: string
}
let arr1: MyType = ['a', 'b', 'c'];
let arr2: MyType = ['a', 'b', 100]; // Error
调用签名
调用签名 Call Signature 描述函数 (参数和返回值) 类型
(parameter: T): U
interface FnType {
(a: number): boolean
}
let fn: FnType = (n: number) => !n;
Class
类具有实例与静态两部分构成。
- implements 实现接口:
class Foo implements T {}
- Construct Signature 构造器签名 =>
new (): T
// 可通过 implements 描述类的实例部分
interface ClassType {
foo: string;
setFoo(str: string): void;
}
// 构造器签名用来描述构造函数
interface ConstructorType {
new (n: number): any;
}
const Foo: ConstructorType = class Foo implements ClassType {
foo: string = 'foo';
setFoo(str: string) {
this.foo = str;
}
constructor(n: number) { }
}
接口继承
接口继承 Interface Extending
- Interface Extending Interfaces 接口继承接口
- Interface Extending Classes 接口继承类
interface Type1 { foo: string }
// 接口继承接口
interface Type2 extends Type1 { bar: string }
const obj: Type2 = {
foo: 'foo',
bar: 'bar',
}
混合类型
混合类型 Hybrid Type
interface MyType {
(n: number): string;
a: number;
}
// 函数 foo 是对象,可添加属性 a
function foo(n: number): string { return '' }
foo.a = 123;
let bar: MyType = foo;
2 类型别名
Type Alias 类型别名使用 type
关键字
type str = string;
let s: str = 'foo';
type Obj = {
a: number;
}
let obj: Obj = { a: 1 };
3 泛型
Generic 泛型好比 JS 中的函数,使用尖括号包裹类型参数: <T>
。
泛型变量
泛型变量 Generic Type Variable:
<T, U...>
- Generic Function 泛型函数
- Generic Interface 泛型接口
- Generic Class 泛型类
泛型函数
// 使用泛型约束参数和返回值类型一致
function identity<T>(arg: T): T {
return arg;
}
// 泛型好比 JS 中的函数,使用时需传入类型
let foo = identity<string>('TS');
// 由于类型推断,TS 会自动推断类型
let bar = identity('TS');
泛型接口
// 使用 interface 描述上面函数
interface GenericInterface1 {
<T>(arg: T): T;
}
// 可将泛型参数当作整个接口的参数
interface GenericInterface2<T> {
(arg: T): T;
}
let baz: GenericInterface2<string> = identity;
泛型类
// 泛型类与泛型接口差不多,`<>`跟在类名后面
class GenericClass<T> {
zeroValue: T;
add: (x: T, y: T) => T;
}
let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function(x, y) {
return x + y;
};
泛型约束
泛型约束 Generic Constraints: <T extends U>
使用泛型定义一个函数,返回参数的 foo 属性。会得到如下错误:
function getFoo<T> (arg: T) {
return arg.foo; // Error: Property 'foo' does not exist on type 'T'
}
使用泛型约束:<T extends FooProp>
interface FooProp {
foo: number;
}
// 泛型 `T` 必须符合接口 `Lengthwise`,即必须包含 `length` 属性
function getFoo<T extends FooProp> (arg: T) {
return arg.foo;
}
getFoo({ foo: 3});
getFoo({ foo: 'foo' }); // Error
结语
本篇介绍了如何自定义类型,下篇介绍类型的检查规则。
本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。