个人复习使用,并不会对示例代码做详细解析
原始类型
| 类型 | 语法 | 特点 |
|---|---|---|
| 任意类型 | any | 顶级类型:代表所有类型,可以接受其他所有类型,也可被除never类型为所有类型接受。使用时无法进行类型检测。不推荐滥用 |
| void类型 | void | 空值,用于函数无返回值 |
| Undefined 类型 | undefined | 联合类型默认带有undefined |
| Null 类型 | null | 无 |
| Never 类型 | never | 表示不存在的值。是所有类型的子类型 |
| 字符串类型 | string | 包括ES6模板字符串 |
| 数字类型 | number | 支持二进制、八进制、十进制和十六进制 |
| 布尔类型 | boolean | true 和 false两种值 |
| 未知类型 | unknown | 顶级类型:可以接受其他所有类型,但本身只能被赋值给 any 类型和 unknown 类型本身。一旦兼容其他类型,就是按照对应类型检测代码 |
| 对象 | object | 表示非原始类型,也就是除number,string,boolean,symbol,null或undefined之外的类型 |
| symbol类型 | symbol | 通过Symbol构造函数创建 |
数组
两种定义方式: Type[] 和 Array<Type> // Type =》 类型
const strArr: string[] = ['1','3']
const strArr2: Array<string> = ['1','3']
let fun = () => 'str'
let arr: {(): string}[] = [fun] //存储返回值为字符串类型的函数
let arr2: Array<() => string> = [fun]
元组
元组类型允许您表示一个已知固定数量的元素的类型的数组
定义 : [Type1, Type2, Type3...]
const address: [string, number] = ["Street", 99];
枚举
枚举是一种为常量数据提供更友好名称的功能
特点 :1.枚举值有默认编号 从0开始依次递加。可以手动设置初始值。2.枚举值是常量类型不能改变。3.枚举值可以当作类型使用
数字枚举
enum Num{
ONE, //0 默认健为0
TWO, //1
THREE = 3 // 3
}
Num.ONE // 0
Num.THREE // 3
Num[0] // ONE
// 使用计算值创建数字枚举
const num = 2
let fun = () => 4
enum Calcuated {
ONE = num,
TWO = fun(),
THREE = 3
}
Calcuated.THREE //3
Calcuated.ONE // 2
Calcuated[4] // TWO
字符串枚举
enum Message {
Error = 'Sorry, error',
Success = 'Hoho, success',
Failed = Error //使用自身的成员
}
Message.Failed // Sorry, error
Message.Error // Sorry, error
异构枚举
同时使用字符串和数字的枚举,称为异构枚举
enum Result {
Faild = 0,
Success = 'success'
}
枚举作为类型使用
enum Animals {
Dog = 1,
Cat = 'success',
}
let a2:Animals.Cat = Animals.Cat
a2 //'success'
常量枚举
常量枚举,不会被编译为JS对象。某些情况下使用,可以提高性能
函数
函数两要素:定义参数类型和返回值类型
let fun: { (arg1: Type, argN: Type): Type }
等价于
let fun: (arg1: Type, argN: Type) => Type
fun = (arg1: Type, argN: Type):Type => {
return TypeValue
}
可选参数
可选参数必须位于,必选参数后面
(arg1: Type, optional?: Type) => ReturnType
剩余参数
(arg1: Type, ...Args: Type[]) => ReturnType
默认参数
xx类型 = xx类型的默认值
(arg1: Type = TypeValue , optional: Type = TypeValue) => ReturnType
重载
重载允许一个函数接受不同数量或类型的参数时,作出不同的处理
1.TS能实现重载的函数只能是使用 function 函数声明定义的的函数
2.重载分为:多次声明的函数头,最后一个实际处理所有函数头的函数
//重载部分
function overloadedMethod(arg1: Type): ReturnType;
function overloadedMethod(arg1: OtherType, arg2: OtherType): ReturnType;
//具体处理重载的函数
function overloadedMethod(arg1: CommonType, arg2: CommonType): CommonReturnType {}
对象
在TypeScript中,就像在JavaScript中一样,对象由键值对组成。我们可以为对象键值对分配类型
let userData: { name: string, age: number } = {
name: 'Max',
age: 27
};
let complex: { data: number[], output: (all: boolean) => number[] } = {
data: [100, 3,99, 10],
output: function(all: boolean): number[] {
return this.data
}
};
接口
特点:1.接口里面的的数据必须实现
接口定义
使用 interface 关键字定义
interface MyInterface {
property: Type;
optionalProp?: Type; // 可选属性
optionalMethod(arg1: Type): ReturnType; // 函数定义
}
接口继承
特点:1.可以继承类
class SomeClass{}
interface Child extends SomeClass {
}
2.接口可以单继承,也可以同时继承多个接口
interface Child extends Parent {
}
interface Child extends Parent1, Parent2 {
}
索引签名和只读属性
只读属性:使用 readonly 修饰符修饰的属性。
特点:只可读取,不可修改。
interface MyInterface {
readonly property: Type;
}
---------------------------------------------------------------------------------------------------------------------
索引签名: 只有 string 和 number 两种。
注意事项:使用了字符串索引签名。其余成员的返回值类型必须和字符串索引保持一致(或者字符串索引返回值类型兼容其余所有成员)
interface MyInterface {
[prop: string]: Type;
[index: number]: Type;
}
联合类型
联合类型 表示取值可以为多种类型中的一种。
语法:type | type2 | typeN...
let a: string | number | boolean | {(): string }
a = 'haha' //ok
a = 1 //ok
类型别名
使用 type 关键字,给一长串代码起一个简洁的名字使用。
type myType = string | number | boolean | {(): string }
let a:myType = 1
a = 'kk'
let b:myType = true
交叉类型
交叉类型是将多个类型合并为一个类型。
interface Sex {
sex: string
}
interface Person {
name: string
age: number
}
type SuperMan = Sex & Person;
const obj: SuperMan = {
name: 'Bob',
age: 18,
sex: 'man'
}
断言
绕过类型检测
1. <类型>值 <Type>Value
2. 值 as 类型 Value as Type
let a = 1;
a.length //error
(a as unknown as string).length // 断言成未知类型,在通过未知类型断言为string类型。访问length属性就不会报错了
类
类的定义
class SomeClass {
property: Type; //定义属性
readonly readProperty: Type; //定义只读属性
defaultProperty: Type = 'default value'; //带有默认值的属性
constructor(property: Type, readProperty: Type) {
this.property = property //属性赋值
this.readProperty = readProperty
}
methodProperty: (arg1: Type) => ReturnType; //定义方法
overloadedMethod(arg1: Type): ReturnType; // 也可以在内部定义函数重载
overloadedMethod(arg1: OtherType): ReturnType;
overloadedMethod(arg1: CommonTypes): CommonReturnTypes {}
}
属性修饰符
public修饰的属性或方法是公有的,可以在任何地方被访问到,默认所有的属性和方法都是public的private修饰的属性或方法是私有的,只能在定义的类中访问。不可在外部和子类中访问protected修饰的属性或方法是受保护的,它和 private 类似,区别是它在子类中也是允许被访问的
class SomeClass {
public prop: Type;
private prop1: Type; //不能被子类访问
protected prop2: Type;
}
class Child extends SomeClass {
constructor() {
super()
this.prop
this.prop2
}
}
----------------------------------------------------------------------------------------------------------------------
可以在 constructor 中使用修饰符,进行简写实例属性。
class SomeClass {
constructor(public prop: Type)
}
等价于
class SomeClass {
prop: Type;
constructor(prop: Type){
this.prop = prop
}
}
- 使用
static修饰符修饰的方法称为静态方法,它们不能被实例化,而是直接通过类来调用
class MyClass {
static readonly prop?: Type;
static staticProperty: Type;
static fun() {
}
}
MyClass.props
MyClass.fun()
继承
继承:使用 extends 关键字
class Parent {}
class Child extends Parent {}
类实现接口:
使用 implements 关键字
interface MyInterface {}
class Child implements MyInterface {}
--------------------------------------------------------------------------------------------------------------------------
特殊情况:
MyInterface extends Parent{} //如果接口继承了父类
class Child extends Parent implements MyInterface {} //子类需要先继承同一个父类,才能实现接口
存取器
ES6的知识,不过TS也支持设置getters/setters用以改变对属性的读取和赋值行为
使用get和set定义
class Animald {
constructor(name) {
this.name = name;
}
get name() {
return 'Jack';
}
set name(value) {
console.log('setter: ' + value);
}
}
抽象类
抽象类是供其他类继承的基类,抽象类不允许被实例化。抽象类中的抽象方法必须在子类中被实现
关键字 abstract 来定义抽象类和子类需要必须实现的方法
abstract class Animal {
constructor(public name) {
this.name = name;
}
abstract sayHi();
abstract get insideName(): string
abstract set insideName(value: string)
}
new Animal('haha') //error
class Dog extends Animal {
sayHi() { }
insideName:string
}
类型保护
1. 使用typeof来判断基础类型 string/number/boolean/symbol中的一种
if (typeof item === 'undefined') {
console.log(item)
} else {
console.log(item()) //error
}
2.使用 instanceof 来判断 class
class Foo {
foo = 123;
}
class Bar {
bar = 123;
}
function doStuff(arg: Foo | Bar) {
if (arg instanceof Foo) {
console.log(arg.foo); // ok
console.log(arg.bar); // Error
} else {
// 这个块中,一定是 'Bar'
console.log(arg.foo); // Error
console.log(arg.bar); // ok
}
}
3.使用 in 操作符可以安全的检查一个对象上是否存在一个属性
interface A {
x: number;
}
interface B {
y: string;
}
function doStuff(q: A | B) {
if ('x' in q) { // in 类似于 for in循环,会遍历对象上的属性
// q: A
} else {
// q: B
}
}
4.自定义类型保护
// 仅仅是一个 interface
interface Foo {
foo: number;
common: string;
}
interface Bar {
bar: number;
common: string;
}
// 自己定义的类型保护!
function isFoo(arg: Foo | Bar): arg is Foo { // is 是关键字
return (arg as Foo).foo !== undefined;
}
// 自己定义的类型保护使用用例:
function doStuff(arg: Foo | Bar) {
if (isFoo(arg)) {
console.log(arg.foo); // ok
console.log(arg.bar); // Error
} else {
console.log(arg.foo); // Error
console.log(arg.bar); // ok
}
}
5.字面量类型保护:主要用于判断联合类型
type Foo = {
kind: 'foo'; // 字面量类型
foo: number;
};
type Bar = {
kind: 'bar'; // 字面量类型
bar: number;
};
function doStuff(arg: Foo | Bar) {
if (arg.kind === 'foo') {
console.log(arg.foo); // ok
console.log(arg.bar); // Error
} else {
// 一定是 Bar
console.log(arg.foo); // Error
console.log(arg.bar); // ok
}
}
泛型
泛型是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。
泛型类
创建一个泛型类
T 是类型占位符, 随便取名字 a b c d....
class Queue<T> { T 会捕捉输入的类型。这里所有的 T 都是同一个类型
private data :T[] = [];
push = (item: T) => this.data.push(item);
pop = (): T | undefined => this.data.shift();
}
简单的使用
const queue = new Queue<number>();
queue.push(0);
queue.push('1'); // Error:不能推入一个 `string`类型,只有 number 类型被允许
----------------------------------------------------------------------------
可以只给内部成员设置泛型,在使用时传入类型
class Utility {
reverse<T>(items: T[]): T[] {
const toreturn = [];
for (let i = items.length; i >= 0; i--) {
toreturn.push(items[i]);
}
return toreturn;
}
}
const child = new Utility()
child.reverse<number>([1,2,3,5])
// 借助TS类型推断简写
child.reverse([1,2,3,5]) // T[] === <number>[]
泛型函数
function reverse<T>(items: T[]): T[] {
const toreturn = [];
for (let i = items.length - 1; i >= 0; i--) {
toreturn.push(items[i]);
}
return toreturn;
}
const sample = [1, 2, 3];
let reversed = reverse(sample); // 这里TS会推断为 T 为number类型. T[] === <number>[]
reversed[0] = '1'; // Error
reversed = ['1', '2']; // Error
reversed[0] = 1; // ok
reversed = [1, 2]; // ok
泛型接口
可以同时使用多个泛型
interface Pair<T, U> {
first: T;
second: U;
}
let pair:Pair<number,string> = {
first: 1,
second: '2'
}
泛型约束
使用 extends 让泛型继承某些条件,来达到约束的作用
interface Lengthwise {
length: number;
}
传入的参数类型必须带有length属性
function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length);
return arg;
}
loggingIdentity(7) // error
loggingIdentity([1, 2, 3, 4]) //ok
loggingIdentity('111') //ok
loggingIdentity({
length: 6 //ok
})
---------------------------------------------------------------------------------------------------
泛型之间互相约束
function copyFields<T extends U, U>(target: T, source: U): T { //T继承U,所以T必须包含U里面的属性
for (let id in source) {
target[id] = (<T>source)[id];
}
return target;
}
let x = { a: 1, b: 2, c: 3, d: 4 };
let y = { a: 1, b: 2, c: 3};
copyFields(x, { b: 10, d: 20 }); // ok
copyFields(y, { b: 10, d: 20 }); // error
泛型参数的默认类型
当使用泛型时没有在代码中直接指定类型参数,从实际值参数中也无法推测出时,这个默认类型就会起作用。
function createArray<T = string>(length: number, value: T): Array<T> {
let result: T[] = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
keyof 索引类型查询操作符
keyof 连接一个类型,返回由这个类型所有属性名组成的联合类型
interface Info {
name: string;
age: number;
}
let infoProp: keyof Info
//等价于 let infoProp:'name' | 'age' 字面量类型
infoProp = 'name' //ok
infoProp = 'age' //ok
infoProp = 'sex' //error
//----------------------------------------------------------------------------------------------------
interface Type1 {
a: string;
b: number;
c: never;
d: null;
e: undefined;
f: object;
}
type Test3 = Type1[keyof Type1] // 过滤属性值为never,null,undefined的类型
Test3 // stirng | number | object
//----------------------------------------------------------------------------------------------------
declare class Person {
private married: boolean;
public name: string;
public age: number;
}
let publicKeys: keyof Person;
// 等价于 let publicKeys: "name" | "age"
// 只能获取 public(公开的)属性
// ------------------------------------------------------------------------------------------------------
索引访问操作符: []
索引访问操作符会返回属性值的类型:
interface Info {
name: string;
age: number;
}
type InfoNameType = Info['name'] //返回name对于的类型:string
等价于
type InfoNameType = string
// K现在是保存T所有的属性,以联合类型形式存在 xx | xx |xx...
function getValue<T, K extends keyof T>(obj: T, names: K[]): Array<T[K]> { //返回值类型 Array<string | number>
return names.map((n) => obj[n])
}
const infoObj = {
name: 'lison',
age: 18,
}
let infoValues: Array<string | number> = getValue(infoObj, ['name', 'age'])
前缀修饰符: + -
映射类型里的readonly或?属性修饰符现在可以使用+或-前缀,来表示修饰符是添加还是移除。
interface Info1 {
age: number;
name: string;
sex: string;
}
// 把属性转换为只读属性 在属性前面添加readonly修饰符。
type ReadonlyType<T> = {
// keyof T 获取T的所有属性 age | name | sex
// in 类似于 for..in循环遍历这些属性
readonly [P in keyof T]: T[P]
// 等价于
// + readonly [P in keyof T]: T[P]
//有一个前缀 + 代表添加readonly修饰符。
}
type ReadonlyInfo1 = ReadonlyType<Info1>
// 现在 ReadonlyInfo1 的属性都是只读的。
// 下面是 ReadonlyInfo1 现在的类型结构 :↓
// type ReadonlyInfo1 = {
// readonly age: number;
// readonly name: string;
// readonly sex: string;
// }
// 现在把readonly修饰符去除掉
type RemoveReadonlyInfo2<T> = {
- readonly [P in keyof T]: T[P]
// readonly 前面有一个 - 号。代表去除属性前面的 readonly 修饰符
}
type Info1WithoutReadonly = RemoveReadonlyInfo2<ReadonlyInfo1>
// 去除了readonly
// 下面是 Info1WithoutReadonly 现在的类型结构 :↓
// type Info1WithoutReadonly = {
// age: number;
// name: string;
// sex: string;
// }