学习TS基础知识

63 阅读3分钟

还不太熟悉TS的掘友们和我一起来学习一些基础的ts知识吧~~

类型推导

let value = 'abcd' 
value = 123456

// 等价于以下代码
let value : string = 'abcd'
value = 123456

类型系统

基本类型

let success : boolean = true 
let age : number = 20 
let name : string = 'akara' 
let u : undefined = undefined 
let n : null = null 

// void 用来代表空值,值只能是undefined或null
let value : void = undefined
value = null

字面量类型

// 字符串字面量类型
let str: 'small' = 'large'

// 数字字面量类型
let num: 1 = 1

// 布尔字面量类型
let boo: true = true

字面量类型可以视为相应类型的子集,如字符串字面量类型可以视为字符串类型的子集。

值得注意的是,用letconst声明变量时,其类型是不同的。

let name = 'aka' // string
const name = 'aka' // 'aka'

数组

数组只可以储存一种数据类型,数组长度可变。

let arr: number[] = [1, 2, 3]
let arr: Array<number> = [1, 2, 3]

元组

元组可以储存多种数据类型,但是元组长度不可变。

let arr: [number, number] = [1, 2]
arr = [1, 2, 3] // 报错

let arr2: [numer, number?] = [1]
arr2 = [1, 2] // 不报错

函数

函数对参数数量和类型有着严格的要求

function A(name?: string): string | undefined { // name的实际类型为string | undefined
    return name
}

function A(name = 'akara'): string { 
    return name
}

函数声明

function sum(x: number, y: number): number { // 函数声明
    return x + y;
}

const mySum = function (x: number, y: number): number { // 函数表达式
    return x + y;
};

const mySum = (x: number, y: number): number => { // 箭头函数表达式
  
}

// 重载函数声明
function A(a: string, b: number): number;
function A(a: number, b: string): string;
function A<T extends string | number>(a: T, b: T): T | undefined {
    if (a === '1') return b
    if (a === 1) return b
    return
}

A(1, '1') // ok
A(1, 1) // 报错

函数类型

const A: (name: string) => void = fn1

const B: {
    (name: string): void;
    id: number;
} = fn2

type C = { // 函数重载
  (): void;
  (name: string): void
}

const D: {
    id: number;
    new (name: string): People;
} = People 

枚举

enum Color {
  One,
  Two
}

Color.One === 0;
Color.Two === 1;
Color[0] === 'One'
Color[1] === 'Two'

any

anyscript === javascript (手动狗头)

let value: any = 'akara'
value = 100 // 不报错
let num: boolean = value // 不报错

let obj: any = {}
obj.getName() // 不报错

unknown

unknown表示某个变量的类型是未知的,也意味着这个变量可能是任意类型的值

let value: unknown;
let num: boolean = value // 报错!这里和any的表现不同

let obj: unknown = {
    getName: function() {}
}

使用时通常搭配类型守卫来narrow该变量的类型范围

let str: unknown;
if (typeof value === 'string') {
  value.toString() // 被断言成string类型
}

never

function fn(value: 1 | 2) {
  switch (value) {
    case 1:
    case 2:
      return value;
    default:
      return neverThrow(value) // 此时value的类型为value。这种写法的好处是当其他人给联合类型时加类型时,此处会报错提醒
  }
}

function neverThrow(value: never): never { // 函数永远不会返回值
  throw new Error(`${value}`)
}

object

可以用来表示对象的类型

let obj: object = {
  name: 'akara'
}

Object

看起来objectObject只有大小写的区别,Object实际上表示的范围更加的广泛,除了表示对象还可以表示数字、字符串、布尔值等基本类型(但不包括NullUndefined)。

const obj: Object = {
    name: 'aka'
}
const obj: Object = 'aka'
const obj: Object = 100
const obj: Object = true

另外,有的时候会看到这种写法{},这和Object是完全等价的。

const obj: {} = { 
    name: 'akara'
}

通常表示对象建议使用object而不是Object

Class

const d: Date = new Date()
const e: Error = new Error('wrong')

class People {
    name = 'aka'
}

const p: People = new People()
const People2: typeof People = People

在TypeScript中,强烈建议只使用class而不是构造函数来声明类,推荐写法:

class People {
  name: string 
  constructor(name: string) {
    this.name = name 
  }
}

TypeScript 有三种访问修饰符, publicprivate 和 protected

  • public 修饰的属性或方法是公有的,可以在任何地方被访问到,默认所有的属性和方法都是 public 的
  • private 修饰的属性或方法是私有的,不能在声明它的类的外部访问
  • protected 修饰的属性或方法是受保护的,它和 private 类似,区别是它在子类中也是允许被访问的
// 修饰符可以写在构造函数的参数中
class Animal {
    public name: string;
    public constructor (name) {
        this.name = name;
    }
}
class Animal {
    readonly name;
    public constructor(name) {
        this.name = name;
    }
}
抽象类
abstract class Animal {
    public name;
    public constructor(name: string) {
        this.name = name;
    }
    public abstract sayHi(): void;
}

class Cat extends Animal {
    public sayHi() {
        console.log(`Meow, My name is ${this.name}`);
    }
}

let cat = new Cat('Tom');
接口实现

接口除了用于描述对象的形状,还可以对类的一部分行为进行抽象

interface Alarm {
    alert(): void;
}

interface Light {
    lightOn(): void;
    lightOff(): void;
}

class Car implements Alarm, Light {
    alert() {
        console.log('Car alert');
    }
    lightOn() {
        console.log('Car light on');
    }
    lightOff() {
        console.log('Car light off');
    }
}

Interface

interface Person {
    readonly id: number;
    name: string;
    age?: number;
    [propName: string]: any;
}

let tom: Person = {
    id: 89757,
    name: 'Tom',
    gender: 'male'
};

tom.id = 9527; // 报错

Type Alias

interfacetype alias作用基本相当,但二者还是有一些区别的,这里挑几个重点的说说

interface A {
    name: string
}
interface B extends A {
    age: number
}

// ----- 分割线 -----

type A = {
    name: string
}
type B = A & {
    age: number
}

泛型

泛型主要被使用在**interface函数**当中。

interface A<T> {
    name: T;
    age: T;
}

let a: A<string> = {
    name: 'aka',
    age: '20',
}
function A<T>(name: T, age: T): T[] {
    return [name, age]
} 
A('a', 'b')

无论是interface还是函数,都存在多个变量的类型,而很多时候我们希望这些变量的类型强关联,所以引入了泛型的概念。

函数有个好处是当我们调用的时候不需要显式传入泛型的值,它会根据函数的参数进行推导。

泛型约束

很多时候我们需要限定泛型的值在某个范围,也就是通过extends来对其进行约束。

function A<T extends { id: number }> (name: T) {
    console.log(name.id)
}
A({ id: 100 })

function B<T extends 'a' | 'b'> (name: T) {
    console.log(name)
}
B('a')

你学会这些基础知识了嘛~