前端入门:快速了解TypeScript高级类型|青训营笔记

76 阅读5分钟

这是我参与「第四届青训营 」笔记创作活动的的第24天

class类

  • 声明成员age,类型为number(没有初始值)
  • 声明成员gender,并设置初始值,此时,可省略类型注解(TS类型推论为string类型)
class Person {
    age: number
    gender = '男'
    //gender: string = '男'
}
const p = new Person()
p.age
p.gender
  • 构造函数:构造函数不需要返回值类型
class Person {
    age: number
    gender: string
    constructor(age: number, gender: string) {
        this.age = age
        this.gender = gender
    }
}
const p = new Person(18, '男')
console.log(p.age, p.gender)
  • 实例方法
class Point {
    x = 1
    y = 2
    scale(n: number) {
        this.x *=n
        this.y *=n
    }
}
const p = new Point()
p.scale(10)
console.log(p.x, p.y)
  • 继承(extends)
class Animal {
    move() { console.log('Moving along!')}
}
class Dog extends Animal {
    bark() { console.log('汪!')}
}
const dog = new Dog()
dog.move()
dog.bark()
  • 继承(implements)
interface Singable {
    sing(): void
}
class Person implements Singable {
    sing() {
        console.log('小苹果')
    }
}
  • 可见性

public(公有的):公有成员可以被任何地方访问,默认可见性(可直接省略)

protected(受保护的):仅对其声明所在的类和子类(非实例对象)中可见

private(私有的):旨在当前类可见,实例对象以及子类都不可见

class Animal {
    public move() { console.log('Moving along!')}
}
class Animal {
    protected move() {console.log('走两步')}
    run() {
        this.move()
        console.log('跑起来')
    }
}
const a = new Animal()
//a.move()不能使用
class Dog extends Animal {
    bark() {
        this.move()
        console.log('汪!')
    }
}
class Animal {
    private run() {
        console.log('Animal内部辅助函数')
    }
    protected move() {
        this.run()
    }
}
  • 只读修饰符

用来防止在构造函数之外对属性进行赋值

只能修饰属性不能修饰方法

readonly关键字后的属性不加类型注解的话,则类型为字面量类型

接口或者{}表示的对象类型,也可以使用readonly

class Person {
    readonly age: number = 18
    constructor(age: number) {
        this.age = age
    }
    //错误演示:
    //readonly setAge() {
    //  this.age = 20
    //}
}
interface IPerson {
    readonly name: string
}
let obj: {readonly name: string } = {
    name: 'jack'
}

类型兼容性

  • 对象类型:y的成员与x相同,则x兼容y
class Piont { x: number; y: number }
class Piont3D { x: number; y: number; z: number }
const p: Point = new Point3D()
  • 接口类型:class和interface之间可以兼容
interface Point { x: number; y: number }
interface Point2D { x: number; y: number }
interface Point3D { x: number; y: number; z: number }
let p1: Point
let p2: Point2D = p1
let p3: Point3D
p2 = p3
interface Point2D { x: number; y: number }
class Point3D { x: number; y: number; z: number }
let p3: Point2D = new Point3D()
  • 函数之间的兼容性

参数数量:参数多的兼容参数少的,或者说参数少的可以赋值给参数多的

type F1 = (a: number) => void
type F2 = (a: number, b: number) => void
let f1: F1
let f2: F2 = f1

参数类型:相同位置的参数类型要相同或兼容

interface Point2D { x: number; y: number }
interface Point3D { x: number; y: number; z: number }
type F2 = (p: Point2D) => void
type F3 = (p: Point3D) => void
let f2: F2
let f3: F3 = f2
f2 = f3
  • 返回值类型

如果返回值类型是原始类型,此时两个类型要相同

如果返回值类型是对象类型,此时成员多的可以赋值给成员少的

//原始类型:
type F5 = () => string
type F6 = () => string
let f5: F5
let f6: F6
f5 = f6
//f6 = f5
//对象类型:
type F7 = () => { name: string }
type F8 = () => { name: string; age:number }
let f7: F7
let f8: F8
f7 = f8

交叉类型

interface Person { 
    name: string
    say(): number
}
interface Contact { phone: string }
type PersonDetail = Person & Contact
let obj: PersonDetail = {
    name: 'jack',
    phone: '133......',
    say() {
        return 1
    }
}
​

交叉类型和接口继承的对比

接口继承会报错,交叉类型不会报错

interface A {
    fn: (value: number) => string
}
interface B {
    fn: (value: string) = string
}
type C = A & B
fn: (value: string | number) => string

泛型

  • 基本使用

在函数名称的后面添加<>,尖括号中添加类型变量

类型变量,一种特殊类型的变量,它处理类型而不是值

给类型变量相当于一个类型容器,能偶捕获用户提供的类型

function id<Type>(value: Type): Type {
    return value
}
const num = id<string>('a')
  • 简化

类型参数推断机制

当无法推断是,就需要传入类型参数

function id<Type>(value: Type): Type {
    return value
}
const num = id(100)
  • 泛型约束

添加约束,缩窄类型取值范围

创建描述约束的接口,要求提供某某属性

interface ILength { length: number }
function id<Type extends ILength>(value: Type): Type {
    console.log(value.length)
    return value
}

多个泛型变量的情况

Key只能是Type所有键中的任意一个,或者是只能访问对象中存在的属性

function getProp<Type, Key extends keyof Type>(obj: Type, key: Key) {
    return obj[key]
}
let person = { name: 'jack', age: 18 }
getProp(person, 'name')
  • 泛型接口
interface IdFunc<Type> {
    id: (value: Type) => Type
    ids: () => Type[]
}
Let obj: IdFunc<number> = {
    id(value) {
        return value
    },
    ids() {
        return [1,3,5]
    }
}
  • 泛型类
class GenericNumber<NumType> {
    defaultValue: NumType
    add: (x: NumType, y: NumType) => NumType
}
const myNum = new GenericNumber<number>()
myNum.defaultValue = 10
  • Partial:将Type的所有属性设置为可选
interface Props {
    id: string
    children: number[]
}
type PartialProps = Partial<Props>
  • readonly:只读
interface Props {
    id: string
    children: number[]
}
type ReadonlyProps = Readonly<Props>
  • Pick:Type中选择一组属性来构造新类型
interface Props {
    id: string
    title: string
    children: number[]
}
type PickProps = Pick<Props, 'id'|'title'>
  • Record:构造一个对象类型,属性键位Keys,属性类型位Type
type RecordObj = Record<'a'|'b'|'c',srting[]>
let obj: RecordObj = {
    a: ['a'],
    b: ['b'],
    c: ['c']
}

索引签名类型

interface AnyObject {
    [key: string]: number
}
Let obj: AnyObject = {
    a: 1,
    abc: 124,
}

映射类型

基于旧类型创建新类型

只能在类型别名中使用,不能在接口中使用

type Propkeys = 'x'|'y'|'z'
type Type1 = { x: number; y: number; z: number }
type Propkeys = 'x'|'y'|'z'
type Type2 = { [Key in PropKeys]: number }

还可以根据对象类型来创建

type Props = { a: number; b: string; c: boolean }
//所有类型变成number
type Type3 = { [key in keyof Props]: number }

索引查询类型

  • 获取属性的类型
type Props = { a: number; b: string; c: boolean }
type TypeA = Props['a']
  • 同时查询多个索引类型
type Props = { a: number; b: string; c: boolean }
//number | string
type TypeA = Props['a'|'b']
//number | string | boolean
type TypeA = Props[keyof Props]

类型声明文件

用来为已存在的JS库提供类型信息

  1. .t文件:
  • 既包含类型信息又可执行代码
  • 可以被编译为.js文件
  • 用途:编写程序代码的地方
  1. .d.ts文件
  • 只包含类型信息的类型声明文件
  • 不会生成.js文件,仅用于提供类型信息
  • 用途:为JS提供类型信息

内置声明文件:Ctrl+鼠标左键来查看内置类型声明文件

  • 创建自己的类型声明文件1
//index.d.ts文件中
type Props = { x: number; y: number }
export { Props }
//.ts文件中
import {Props} from './index'
Let p2: Props = {
    x: 10,
    y: 22
}
  • 创建自己的类型声明文件2
//在js中
Let count = 10
Let songName = '痴心'
let position = {
    x: 0,
    y: 0
}
function add(x,y) {
    return x + y
}
function changeDirection(direction) {
    console.log(direction)
}
const fomartPoint = point => {
    console.log('当前坐标',point)
}
export { count,songName,position,}
//在.d.ts中
declare Let count: number
declare Let songName: string
interface Point {
    x: number
    y: number
}
declare Let position: Point
declare function add(x: number, y: number): number
declare function changeDirection(
    direction: 'up'|'down'|'left'|'right'
): void
type FomartPoint = (point: Point) => void
declare const fomartPoint: FomartPoint
export { count, songName,position add,}