likes
comments
collection
share

一文上手 TypeScript 基础

作者站长头像
站长
· 阅读数 15

TypeScript 是 JavaScript 的超集,在 JavaScript 的基础上增加了静态类型检查。

数据类型

TypeScript 具有 JavaScript 的所有类型,包括 boolean, number, string, undefined, null, symbol 及 object, 并增加了 enum, tuple, void, any 和 never 这几种类型。

1. TypeScript 中的基础类型

基础类型包括 boolean, number, string, undefined, null, symbol,对应 JavaScript 的原始数据类型。在 TypeScript 中声明也很方便,具体看下面的实例。

// boolean
let show: boolean = true

// number
let num: number = 1

// string
let name: string = 'myname'

// undefined
let u: undefined = undefined

// null
let n: null = null

undefinednull 是所有类型的子类型。类似下面这样赋值不会报错。

let u: undefined = undefined
let num: number = u

2. 数组

常见的定义数组的方式有两种

  • <elemType>+[] 表示和约束数组,
  • Array<elemType> 数组范型来表示数组。
// elemType + []
let arr: number[] = [1, 2, 3, 4, 5]

// Array<elemType>
let arr:Array<number> = [1, 2, 3, 4, 5]

// 任意类型
let arr: any[] = ['a', 2, null]

3. 枚举

enum 类型可以赋予一组取值有意义的名字,可以用来创建有区别的用例。 枚举成员被赋予值为从 0 开始递增的数字,同时进行反向映射。

enum Direction {
    Up,
    Right,
    Down,
    Left,
}

Direction['Up'] === 0 // true

// 反向映射
Direction[0] === 'Up' // true

也可以手动赋值,未赋值的枚举项接着上一个递增。

enum Direction {
    Up = 1,
    Right,
    Down,
    Left,
}

Direction['Right'] === 2 // true

4. 元组

Tuple 类型可以用来表示已知元素数量和类型的数组,并且类型不必相同。

let person: [string, number] = ['myname', 20]

5. void, any 和 never

TypeScript 中可以用

  • void 表示没有任何返回值的函数,
  • any 表示返回任何类型的值,
  • never 表示永远不存在返回值的函数或者永不为真的变量。
// void
const foo: void = () => {
    console.log('foo')
}

// any
let anyThing: any = 'jieiyi'

// never
// 示例暂定

7. 函数

常用的定义函数的方式有

  • 函数声明
  • 函数表达式
// 函数声明
function add(x: number, y: number): number {
    return x + y
}

// 函数表达式
const add = (x: number, y: number): number => {
    return x + y
}

// 可选参数
const add = (x: number, y: number, z?: number): number => {
    if (z) {
        return x + y + z
    } else {
        return x + y
    }
}

8. 类

8.1 公共/私有/受保护修饰符(public/private/protected)

这几种修饰符都可以修饰属性和方法,各自效果如下,

  • public 默认修饰符,无限制。
  • private 限制在类的外部访问,不能继承。
  • protected 限制外部访问,但可被继承。
// public
class Girl {
    public name: string
    constructor(name: string) {
        this.name = name
    }
}
const myname = new Girl('myname')
console.log(myname) // myname

// 以上的写法也可以简化,仅在需要的时候指定修饰符
class Girl {
    constructor(public name: string) {
        this.name = name
    }
}
// private
class Girl {
    constructor(private name: string) {
        this.name = name
    }
}
const myname = new Girl('myname')
console.log(myname) // 编译错误
// protected
class Girl {
    constructor(protected name: string) {
        this.name = name
    }
}

class TeenGirl extends Girl {
    constructor(name: string, private age: number) {
        super(name)
        this.age = age
    }
    public getMessage = () => {
        return `${this.name}: ${this.age}`
    }
}

const myname = new TeenGirl('myname', 18)
console.log(myname.getMessage()) // myname: 18
console.log(myname.name) // 编译错误

8.2 只读修饰符(readonly)

设置属性为只读,只有在声明或者构造函数中被初始化,不能在外部改变。

class Girl {
    constructor(readonly name: string) {
        this.name = name
    }
}
const myname = new Girl('myname')
myname.name = 'myname' // 编译错误

8.3 抽象修饰符(abstract)

定义抽象类,定义其他继承子类的基类。

  • 抽象类不能被实例化。
  • 抽象类中的抽象方法必须被子类实现。
abstract class Girl {
    constructor(readonly name: string) {
        this.name = name
    }
    // 定义抽象方法
    abstract getMessage()
}

class TeenGirl extends Girl {
    constructor(name: string, private age: number) {
        super(name)
        this.age = age
    }
    // 必须实现 Girl 类中定义的 getMessage 方法
    public getMessage = () => {
        return `${this.name}: ${this.age}`
    }
}

const myname = new TeenGirl('myname', 18)

类型的复杂操作

1. 类型推论

TypeScript 会在没有指定类型的时候推测出一个类型,这就是类型推论。

let name = 'myname'
name = 007 // 编译错误,默认推论 name 的类型为 string

2. 联合类型

取值可以是多种类型中的一种。当访问联合类型的属性和方法的时候只能访问共有属性和方法。

let name: string | number
name = 'myname'
name = 007

// 访问属性和方法
const getName = (name: string | number): string => {
    return name.toString() // toString 方法是 string 和 number 属性共有的
}

const getNameLen = (name: string | number): number => {
    return name.length() // length 方法不是 string 和 number 属性共有的,会编译错误
}

3. 类型别名

可以给类型取一个新名字。用 type 修饰符创建别名。

type nameType = string | number

let name: nameType
name = 'myname'
name = 007

4. 字符串字面量

约束取值只能为给定的字符串。

type EventNames = 'click' | 'scroll'
const handleEvent = (element: Element, event: EventNames): any => {
    element.addEventListener(event, () => {
        event === 'click' && element.style.filter = 'grayscale(1)'
    })
}

handleEvent(document.querySelector('html'), 'click')

5. 类型断言

用来手动指定一个值的类型。

  • value
  • TSX 中一般用 as 关键字。
const getNameLen = (name: string | number): number => {
    if (name as string) {
        return name.length
    } eles {
        name.toString().length
    }
}

TypeScript 进阶

1. 接口(Interface)

通过接口来约束对象的类型。

1.1 对象与接口

通过接口来描述对象的形状。

  • 变量形状必须与接口保持完全一致
  • ? 可用来表示可选属性
  • 诸如 [propName: string] 的方法可以加入任意属性,但确定属性和可选属性的类型都必须是它的类型的子集
interface IGirl {
    name: string | number
    age?: number
    [propName: string]: any
}

const myname: IGirl {
    name: 'myname',
    age: 18,
    fruit: 'strawberry',
}

2. 泛型

在定义对象的时候不预先指定具体类型,而是在使用的时候才指定。

2.1 示例: echo 命令

echo 命令是一个传声筒,会原样返回任何它传入的值。

// 希望效果
echo('myname') // myname
echo(007) // 007

上面传入了 string 类型和 number 类型,简单写法可以如下,

const echo = (value: any): any => value

不过显而易见,我们丢失了返回值的类型。采用泛型,可以很好的解决这个问题。

const echo<T> = (value: T): T => value

上面函数中,给函数 echo 添加了类型变量 TT 帮助捕获用户传入值的类型,并传给函数,最后传给函数值。现在我们明确知道返回值的类型了。

参考

转载自:https://juejin.cn/post/7267539993966821411
评论
请登录