TypeScript-基础知识
可选参数
用?关键字来表示该参数可选
可选参数必须放在后面
const fn = (x: string, y?: string): string{ if (y) { return x + y } return x //8}const fn1 = fn('8')剩余参数
...关键字定义一个剩余参数
剩余参数接收前面接受不完的参数(如果有)
const Fn1: (x: string, ...args: string[]) => string[] = function (x: string, ...args: string[]): string[] { console.log(x) // a args.unshift(x) console.table(...args) //['a', 'b', 'c', 'd', 'e'] return args}
const fn1 = Fn1('a', 'b', 'c', 'd', 'e')console.log(fn1)函数重载
重载的必要条件:
-
两个或以上重名函数,函数参数可能不相同(函数重载声明)
-
函数声明 缺点:函数重载声明过多 解决方案:使用泛型可重构的函数重载
//函数重载声明function add (x: string, y: string): stringfunction add (x: number, y: number): number
``
//函数声明function add (x: string | number, y: string | number): string | number { if (typeof x === 'string' || typeof y === 'string') return `${ x } - ${ y }` else return x + y}
const add1 = add(10, 20) //30const add2 = add(20, '20') //errorconst add3 = add('str', 'ing') //stringconst add4 = add('30', '40') //使用泛型可实现少代码的函数重载
//重构以上代码
function add<T> (x: T, y: T): T { if (x<string> || y<string>) { return `${ x } - ${ y }` } else { return x + y }}
const add1 = add<number>(10, 20) //30const add2 = add<number | string>(20, '20') //errorconst add3 = add<string>('str', 'ing') //stringconst add4 = add<string>('30', '40')class
//基类/超类class Person {
}
//派生类(通过extends继承的类就称为派生类,被继承的类就叫基类/超类,之间的关系就叫父子类)class DerivedClass extends Person {
}
const person = new Person()const derivedClass: Person = new DerivedClass()泛型
应用场景: 在初始化时不确定要传入的类型,只有在传入时才确定的类型使用
单个泛型参数
function add<T> (x: T, y: number): Array<T> { const arr = string[] = [] for (let i = 0; i < y; i++) { arr.unshift(x) } return arr}
const str = add('a', 'b', 'c')interface IAni { cont: number}
function <T> (x: <T extends IAni>): T {}类型
type定义一个类型
//定义type Name = stringtype NameResolver = () => stringtype NameOrResolver = Name | NameResolver
//使用const name: Name = 'lisa'
//n的类型可能是字符串,或者是一个函数的返回值为字符串 返回类型:字符串function getName (n: NameOrResolver): Name { //类型断言 <string> 断定此时的类型为string if (n<string>) { //返回该字符串 return n } //执行该函数 else { return n() }}
const str = getName('str')类型断言
使用类型断言来给变量明确的类型
使用 <类型>断定此时为一个<>里的类型
<> 尖括号形式来表示类型断言
function (x: string | number): number | undefined { if (x <number>) { return x } else if (isNaN(x <string>)) { return Number(x) } else { return 'not a number' }}as 关键字表示类型断言
const arr = [1, 2, 3, 4]arr.find(e => e > 2) //ts报错 此时ts提示arr的类型为number | undefinedconst arr1 = arr as number //给arr添加类型断言 就不会报错arr.find(e => e > 2) //3别名
可以为interface接口,class类,function函数等起一个别名
type Name:string
function (n: Name) { return n}接口
定义一串来限制对象/函数/类的属性类型
//定义一个接口明确限制对象的属性类型interface Person { id: number, name: string, age: number | string, gender: string, isShow?: boolean}
//定义一个接口来限制函数的参数类型interface IFn { //调用签名 (str1: string, str2?: string): string}
const obj: Person = { id: 1, name: 'lisa', age: '20', gender: 'woman',}
const fn: IFn = (str1: string, str2?: string): string => { if (str2) { return str1 + str2 } return str1}[] 关键字给动态对象类型添加接口
例 [属性名称(任意):属性类型] :类型
interface Person { [key: string]: string //限定属性类型为字符串 则对象的值必须也是字符串类型}
const obj = {}obj.name = 'lisa'obj.age = 18 //报错 不是字符串readonly 只读属性 限定接口类型的值不可修改,一旦赋值之后就不能修改
interface Type { readonly name: string}
const obj: Type = { name: 'lisa'}obj.name = 'sum' // err 无法分配到 "name" ,因为它是只读属性其他
声明文件
- 自定义类型提示(Vanilla)
declare var xxx: (变量: 类型) => 返回类型类
描述一类事物的抽象特征
类成员(属性)
语法
修饰符 成员名 = 值
写法
class 类名{ public/private/proected name: type = value //不推荐}语法
public/proected/private成员名 : 类型constructor(成员名:类型){ this.成员名 = 成员名}写法
class ClassName { public name: type
constructor (name: string) { this.name = name }}抽象类:
通过adstract关键字定义一个抽象类
-
抽象类不能实例化
-
抽象类的价值是被当作
基类/超类来使用 主要给派生类定义类型和抽象的方法 -
抽象类可以具体描述
-
抽象类在抽象方法时不用
{}但需要空的返回值类型void -
抽象类不建议/不经常使用抽象属性
abstrace
class Person { abstract name: string = 'name' //不推荐 abstrace
eat (): void //空的返回值 abstract sayHi (): void { //可以具体书写方法 console.log("hi") }}类定义
class Person {}readonly 只读属性
class Person { //前缀修饰符 readonly name: string = 'defaultName' //参数修饰符 使用了参数修饰符,该类中就有该只读成员变量,不用定义即可访问 //只有类中的构造函数可以修改readonly只读属性 其他地方均不可以修改 constructor (readonly name: string = 'defaultName') { this.name = name //可以成功修改,意义不大 this.name = '我被修改了' }
}
const person: Person = new Person('lisa')public 公共的
在任何地方都可以使用 class类中默认是public修饰符
class Person { //定义变量 需明确赋值 public name: string = 'lisa'
//定义对象 public obj = { name: 'lisa summer' age: 19 }
//定义方法 public fullName () {
}}protected 受保护的
只能在本类或者是继承的派生类中使用
class Person { //只能在本类和派生类使用 protected name: string = 'lisa'}
class Derived extends Person { construstor (name: string) { super(name) }}
const person: Person = new Person()const derived: Derived = new Derived()console.log(deriver.name) // errorprivate 私有的
只能在本类中使用, 派生类 其他类 和类外部都不能使用
bug: 编译是提示错误 但可以正常访问 加上 as any时也可以获取到
用 #变量代替private 在es2020中使用私有属性#时ts转成js时会将#私有属性编译成weakMap来编译成js
class Person { private name: string = 'summer' #firstName: string = 'lisa'}
class Derived extends Person { construotr () { super() }}
const person: Person = new Person()const derived: Person = new Derived()
console.log(derive.name) //编译是提示错误 但浏览器正常输出值 summerconsole.log((derive as any).name) // 编译正常且不报错console.log(derived.firstName) // 编译报错 输出undefinedstatic 静态成员
可直接使用 类名 . 静态成员来访问静态成员
类的constructor构造器不可以使用static静态前缀
静态成员不可以通过constructor构造器的this来访问
class Person { static constructor () {} //error static name: string = 'lisa'
public constructor () { this.name = name //error }
static add (num1: number, num2: number): number { return num1 + num2 }}
console.log(Person.name) //lisaconsole.log(Person.add(1, 2)) // 3