typeScript基本使用
ts中的数据类型
同js的数据类型: undefined、Nul、boolean、string、number、Symbol、Object、Array、Function
其他数据类型:void、any、never、元组、枚举、接口、泛型、高级类型
基本类型
//boolean
let bool: boolean = true
//number
let num: number = 1
//string
let str: string = 'abc'
//undefined
let unde: undefined = undefined
//nul
let nul: null = null
// symbol
let sy: symbol = Symbol()
//多类型
let abc: boolean | string | number | undefined | null = 123
数组
//Array
let arr1: number[] = [1, 2, 3]
let arr2: Array<number> = [1, 2, 3]
let arr3: Array<number | string> = [1, 2, 3, "4"]
元组
元组表示一个确定长度和类型的数组
元组可以通过使用数组方法(比如push)改变值,但是访问时不能超出其规定的界限
// 元组
let tuple: [number, string] //指定tuple是一个长度为2并且第一个数据是number第二个数据是string的数组
tuple = [0, '1'] //赋值成功
tuple[2]=1 //报错
tuple.push(2) //给元组增加一项
console.log(tuple) //[0,'1',2]
tuple[2] //报错
函数
// 函数
// 声明接受两个number类型的参数并且函数返回类型为number
// 函数返回类型可以不声明,ts会自动推导
let fn = (x: number, y: number): number => x + y
//定义一个函数类型
let fnType: (x: number, y: number) => number
fnType=(a, b) => a + b //赋值的时候不用在声明类型
对象
// 对象
// 直接声明object类型
let obj: object = { x: 1, y: 2 }
obj.x=11 //报错 类型“object”上不存在属性“x”。
// 声明object的属性及属性对应的类型
let obj1: { x: number; y: number } = { x: 1, y: 2 }
obj1.x=11
void
void表示没有任何类型,通常用于函数表名函数没有返回值
// void
let fn: () => void
let fn1 = () => {}
any
any表示任意类型,可以理解为没有指定类型
// any
let num: any = 4
num='4' //ok
never
never类型表示的是那些永不存在的值的类型
// 返回never的函数必须存在无法达到的终点
let error = (): never => {
throw new Error("error")
}
let endless = () => {
while (true) {}
}
枚举(enum)
枚举类型是对JavaScript标准数据类型的一个补充
数字枚举
// 数字枚举
// 默认从0开始依次递增
enum enumA {
a,
b,
c,
d,
}
console.log(enumA.a) // 0
// 使用枚举值
let c: enumA = enumA.c //2
// 指定开始值
enum enumB {
a=100,
b,
c,
d,
}
console.log(enumB.a) // 101
console.log(enumB) //{100: "a", 101: "b", 102: "c", 103: "d", a: 100, b: 101, c: 102, d: 103}
console.log(enumB[100]) //a
从打印结果可以看出,数字枚举键和值可以反向映射,其实现如下:
var enumB;
(function (enumB) {
enumB[enumB["a"] = 100] = "a";
enumB[enumB["b"] = 101] = "b";
enumB[enumB["c"] = 102] = "c";
enumB[enumB["d"] = 103] = "d";
})(enumB || (enumB = {}));
字符串枚举
字符串枚举不支持反向映射
enum enumC {
a = "a",
b = "b",
}
console.log(enumC) //{a: "a", b: "b"}
异构枚举
字符串枚举和数字枚举混用就是异构枚举
enum enumD {
a,
b = enumC.a,
c = 1 + 3,
// computed member
d = Math.random(),
e = '123'.length,
f = 4,
g
}
// 编译一下
var enumD;
(function (enumD) {
enumD[enumD["a"] = 0] = "a";
enumD[enumD["b"] = enumC.a] = "b";
enumD[enumD["c"] = 4] = "c";
// computed member
enumD[enumD["d"] = Math.random()] = "d";
enumD[enumD["e"] = '123'.length] = "e";
enumD[enumD["f"] = 4] = "f";
enumD[enumD["g"] = 5] = "g";
})(enumD || (enumD = {}));
通过编译后的代码可以看出,当枚举的值是表达式的时候不会立马去计算表达式的值
常量枚举
用const声明的枚举就是一个常量枚举,常量枚举编译之后不会产生任何代码
const enum enumE {
a,
b,
c,
}
let a: enumE = enumE.a
// 编译后
let a = 0 /* a */;
接口(interface)
接口可以理解为规范或者约束,预先把对象的结构定义好
对象类型接口
interface List {
name: string
readonly id: number // readonly标明此属性为只读属性不能被修改
age?: number //?标明此属性可以有也可以没有
[x: string]: any //标明允许对象可以有其他任意数量的属性
}
函数类型接口
interface Add {
(x: number, y: number): number
}
// 和函数声明是一样的
let Add1: (x: number, y: number) => number
// 也可以使用类型别名
type Add2 = (x: number, y: number) => number
let add: Add = (a, b) => a + b
混合型接口
interface Lib {
(): void //标明lib是一个没有返回值的函数
version: string
doSomething(): void
}
function getLib() {
let lib = (() => {}) as Lib //用as进行类型断言
lib.version = "1.0.0"
lib.doSomething = () => {}
return lib
}
let lib1 = getLib()
lib1()
lib1.doSomething()
类
基本使用
class Dog {
// private constructor(name: string) { 给构造函数加上private此类不能被继承不能被实例化
// this.name = name
// }
// protected constructor(name: string) { 给构造函数加上protected此类不能被实例化只能被继承
// this.name = name
// }
constructor(name: string) {
this.name = name
}
public name: string = "dog" //public 默认修饰符 不写就是public
private age: number = 10 //private 私有修饰符 只能被类本省调用不能被实例调用
protected eat() {} //protected 受保护修饰符 受保护的变量只能在本类和子类中使用,不能在实例中使用
readonly sex: string = "1" //readonly只读属性,不能被修改
static food: string = "bones" //static静态修饰符 只能通过类来访问不能被实例访问,可以被继承
run() {}
sleep() {
console.log("Dog sleep")
}
}
let dog = new Dog("tom")
dog.age //报错 属性“age”为私有属性,只能在类“Dog”中访问
dog.eat() //报错 属性“eat”受保护,只能在类“Dog”及其子类中访问
dog.food //
// 编译后
class Dog {
constructor(name) {
this.name = "dog";
this.age = 10;
this.sex = "1";
this.name = name;
}
eat() { }
run() { }
sleep() {
console.log("Dog sleep");
}
}
Dog.food = "bones";
抽象类
抽象类只能被继承,不能创建实例
abstract class Animal {
eat() {
console.log('eat')
}
abstract sleep(): void //定义抽象方法,具体方法内容由子类去实现
}
class Dog extends Animal {
sleep() {
console.log('Dog sleep')
}
}
let dog = new Dog()
dog.eat()
dog.sleep()
类和接口的关系
接口是规范,可以用接口的规范实现一个类
接口只能约束类的公有成员
接口也可以被继承
接口可以继承类
interface Human {
name: string;
eat(): void;
}
class Asian implements Human {
constructor(name: string) {
this.name = name;
}
// private name: string 接口上的属性必须为public
name: string
eat() {}
age: number = 0
sleep() {}
}
//接口Man继承Human 并增加一个自己的方法
interface Man extends Human {
run(): void
}
interface Child {
cry(): void
}
//接口Boy继承Man和Child 取并集 boy上有4个属性
interface Boy extends Man, Child {}
let boy: Boy = {
name: '',
run() {},
eat() {},
cry() {}
}
class Auto {
state = 1
}
interface AutoInterface extends Auto {}
//Bus继承于Auto已经有state属性
class Bus extends Auto implements AutoInterface {
}
泛型
泛型不预先确定数据类型,具体的数据类型在使用的时候确认
// 泛型函数
function fn<T>(value: T): T {
console.log(value);
return value;
}
fn<string[]>(['a', ',b', 'c']) //使用的时候声明类型
fn(['a', ',b', 'c']) //使用类型推导
// 声明一个泛型函数
type Fn = <T>(value: T) => T
// 泛型接口
interface Inter<T> {
(value: T): T
}
let myInter: Inter<number> = fn //使用泛型接口需要声明类型
myInter(1)
// 泛型类
class C<T> {
run(value: T) {
console.log(value)
return value
}
}
泛型不能用于类的静态属性
泛型约束
不同类型具有不同的属性,使用类型下的属性是必须要加上类型约束
interface Length {
length: number
}
function logLength<T extends Length>(value: T): T {
console.log(value, value.length);
return value;
}
logLength('12')
logLength({ length: 3 })
logLength(12) //报错 12不存在length属性
类型断言
告诉编译器我确定这个数据的类型,听我的,你不要报错~~
interface Foo {
bar: number
}
let foo = {} as Foo // as 语法
let foo = <Foo>{} // <>语法
let someValue: any = "this is a string"
let strLength: number = (someValue as string).length // as 语法
let strLength1: number = (<string>someValue).length // <>语法
类型保护
enum Type { Strong, Week }
class Java {
helloJava() {
console.log('Hello Java')
}
java: any
}
class JavaScript {
helloJavaScript() {
console.log('Hello JavaScript')
}
js: any
}
// 函数守卫
function isJava(lang: Java | JavaScript): lang is Java {
return (lang as Java).helloJava !== undefined
}
function getLanguage(type: Type, x: string | number) {){
let lang = type === Type.Strong ? new Java() : new JavaScript()
// 不使用类型保护 一直使用类型断言
if ((lang as Java).helloJava) {
(lang as Java).helloJava();
} else {
(lang as JavaScript).helloJavaScript();
}
// 用instanceof判断是哪个实例
if (lang instanceof Java) {
lang.helloJava()
} else {
lang.helloJavaScript()
}
// 用in判断属性
if ('java' in lang) {
lang.helloJava()
} else {
lang.helloJavaScript()
}
// 用typeof判断
if (typeof x === 'string') {
console.log(x.length)
} else {
console.log(x.toFixed(2))
}
// 用自定义函数
if (isJava(lang)) {
lang.helloJava();
} else {
lang.helloJavaScript();
}
}
交叉类型和联合类型
交叉类型:将多个类型合并成一个类型,新类型具有所有类型特性
interface DogInterface {
run(): void
}
interface CatInterface {
jump(): void
}
let pet: DogInterface & CatInterface = {
run() {},
jump() {}
}
联合类型:取值可以是多个类型的一种
// 类型联合
let a: number | string = 1
// 取值联合 限定取值范围
let b: 'a' | 'b' | 'c'
let c: 1 | 2 | 3
其他应用类型
索引类型
interface Obj {
a: number;
b: string;
}
let key: keyof Obj // let key: "a" | "b"
let value: Obj['a'] // let value: number
// 示例
let obj = {
a: 1,
b: 2,
c: 3
}
function getValues<T, K extends keyof T>(obj: T, keys: K[]): T[K][] {
return keys.map(key => obj[key])
}
console.log(getValues(obj, ['a', 'b']))
console.log(getValues(obj, ['d', 'e'])) // 报错
映射类型
interface Obj {
a: string;
b: number;
}
type ReadonlyObj = Readonly<Obj>
// type ReadonlyObj = {
// readonly a: number;
// readonly b: string;
// }
type PartialObj = Partial<Obj>
// type PartialObj = {
// a?: number | undefined;
// b?: string | undefined;
// }
type PickObj = Pick<Obj, "a" | "b">
// type PickObj = {
// a: number;
// b: string;
// }
type RecordObj = Record<"x" | "y", Obj>
// type RecordObj = {
// x: Obj;
// y: Obj;
// }
条件类型
// T extends U ? X : Y
type TypeName<T> =
T extends string ? "string" :
T extends number ? "number" :
T extends boolean ? "boolean" :
T extends undefined ? "undefined" :
T extends Function ? "function" :
"object";
type T1 = TypeName<string> // type T1 = "string"
type T2 = TypeName<string[]> // type T2 = "object"
// (A | B) extends U ? X : Y 等价于 (A extends U ? X : Y) | (B extends U ? X : Y)
type T3 = TypeName<string | string[]> // type T3 = "string" | "object"
type Diff<T, U> = T extends U ? never : T
type T4 = Diff<"a" | "b" | "c", "a" | "e"> // type T4 = "b" | "c"
type NotNull<T> = Diff<T, null | undefined>
type T5 = NotNull<string | number | undefined | null> // type T5 = string | number
// Extract<T, U> 抽取T,U中的交集
type T6 = Extract<"a" | "b" | "c", "a" | "e"> //type T6 = "a"
// ReturnType<T> 获取函数返回值的类型
type T8 = ReturnType<() => string>