typescript - 我想要注意的点

本贴最后更新于 1518 天前,其中的信息可能已经事过景迁

学习 TS 有一段时间了,目前很多的一些项目都开始往 TS 转,在写的过程中总会遇到一些大大小小的问题,然后也没人一起学习与帮助,还是蛮吃力的。

所以将在整体的学习过程中,我认为比较重要的点都在这记录下来,以后遇到的一些问题都会往这里补充吧,如果大家有想一起分享的,都可以写在评论区,然后我再补充到文章中,咱们社区也能建立起好的前段氛围呀huaji trollface

函数剩余参数的类型定义

function push(array: any[], ...items: any[]) {
    items.forEach(function(item) {
        array.push(item);
    });
}

let a = [];
push(a, 1, 2, 3);

函数中重载的类型定义

function reverse(x: number | string): number | string {
    if (typeof x === 'number') {
        return Number(x.toString().split('').reverse().join(''));
    } else if (typeof x === 'string') {
        return x.split('').reverse().join('');
    }
}
# 输入 number 出 number,输入 string 出 string,但是上面显然不能满足
function reverse(x: number): number;
function reverse(x: string): string;
function reverse(x: number | string): number | string {
    if (typeof x === 'number') {
        return Number(x.toString().split('').reverse().join(''));
    } else if (typeof x === 'string') {
        return x.split('').reverse().join('');
    }
}

类型断言

#1. 值 as 类型
#2. <类型>值
# 作用1:确定联合类型中的类型
interface Cat {
    name: string;
    run(): void;
}
interface Fish {
    name: string;
    swim(): void;
}

function getName(animal: Cat | Fish) {
    return animal.name;
}
function isFish(animal: Cat | Fish) {
    # 这里会报错的
    if (typeof animal.swim === 'function') {
        return true;
    }
    return false;
}
----- 需要了解返回的是那个类型

function isFish(animal: Cat | Fish) {
    # 利用 as 表示此时的 animal 为 Fish 类型
    if (typeof (animal as Fish).swim === 'function') {
        return true;
    }
    return false;
}

双重断言

  • 任何类型可以被断言为 any
  • any 可以被断言为任何类型

所以可以利用 as any as Foo 将任何一个类型断言为另一个类型

interface Cat {
    run(): void;
}
interface Fish {
    swim(): void;
}

function testCat(cat: Cat) {
    return (cat as any as Fish);
}
# 当然使用双重断言是非常不友好的,除非迫不得已,尽量别使用

类型断言解决泛型

function getCacheData(key: string): any {
    return (window as any).cache[key];
}

interface Cat {
    name: string;
    run(): void;
}

const tom = getCacheData('tom') as Cat;
tom.run();
---- 类型断言去掉 any
function getCacheData<T>(key: string): T {
    return (window as any).cache[key];
}

interface Cat {
    name: string;
    run(): void;
}

const tom = getCacheData<Cat>('tom');
tom.run();

字符串约束取值

有时候,比如某个参数只能是 a 或者 b 的时候

# 首先可以这么写
let func = (str: 'top' | 'end') => {}

# 同时也可以字符串字面量类型
# 字符串字面量类型用来约束取值只能是某几个字符串中的一个。
type Flow = 'top' | 'end'
let func = (str: Flow) => {}

# 还可以使用类型别名
type Flow = {
    top: string,
    end: string
 }
let func = (str: keyof Flow) => {}

元组与数组泛型的联合类型

元素可以确定数据类型,但是不能超过范围,可以理解元组可以固定数组长度,超出范围并不能保证其类型。

# 基本定义
let tom: [string, number];
tom = ['Tom', 25];
tom.push('male');
tom.push(true); // Argument of type 'true' is not assignable to parameter of type 'string | number'.

# 数组泛型与元组的去呗
type Name = string|number 
let arr: Array<Name> = ['Tom', 25]
arr = [25, 'Tom']

let tom: [string, number];
tom = ['Tom', 25]; // true
tom = [25, 'Tom'] // false  Type 'string' is not assignable to type 'number'.(2322)

快速生成一个 ts 模板库

npm install -g tsdx

命名空间的作用( namespace

类似于闭包的作用(立即执行函数):作用域的另一种抽象,为了防止相同名称带来的冲突。

// 命名空间
namespace Utility {
    export const log = (msg:string) => console.log(msg)
    export const error = (msg:string) => console.error(msg)
}
Utility.log('hello')
Utility.error('error')

箭头函数泛型怎么写

# <T> 不写 reverse<T> 而是 reverse = <T>()=>{}
const reverse = <T>(items: T[]): T[] => {
    let toreturn = []
    for(let i = items.length - 1; i>=0; --i) {
        toreturn.push(items[i])
    }
    return toreturn
}

const sample = [1, 2, 3]
let reversed = reverse(sample)
console.log(reversed)

const strs = ['b', 'a', 'c']
let reversed1 = reverse<string>(strs)
console.log(reversed1)

交叉类型怎么写

比如需要将两个对象进行合并,这时候需要使用交叉类型,类似于 Java 一样的交叉类型

const extend = <T extends object, U extends object>(a:T, b:U):T&U=>  {
    const result = <T&U>{}
    for(let id in a) {
        // 注意这里需要加上 <T>
        (<T>result)[id] = a[id]
    }
    for(let id in b) {
        // 注意这里需要加上 <T>
        if(result.hasOwnProperty(id)) (<U>result)[id] = b[id]
    }
    return result
}

const x = extend({a:'hello'}, {a:1,b:42})

类型不存在怎么办

比如 Window 之类的都是存在,加入某个公共的类不存在怎么办呢,可以创建一个 global.d.ts 声明一些需要的类型。

重载解决可选参数声明

function padding(a: number, b?: number, c?: number, d?: any) {
  if (b === undefined && c === undefined && d === undefined) {
    b = c = d = a;
  } else if (c === undefined && d === undefined) {
    c = a;
    d = b;
  }
  return {
    top: a,
    right: b,
    bottom: c,
    left: d
  };
}
# -------
// 重载
function padding(all: number):any;
function padding(topAndBottom: number, leftAndRight: number):any;
function padding(top: number, right: number, bottom: number, left: number):any;
// Actual implementation that is a true representation of all the cases the function body needs to handle
function padding(a: number, b?: number, c?: number, d?: number) {
  if (b === undefined && c === undefined && d === undefined) {
    b = c = d = a;
  } else if (c === undefined && d === undefined) {
    c = a;
    d = b;
  }
  return {
    top: a,
    right: b,
    bottom: c,
    left: d
  };
}

padding(1); // Okay: all
padding(1, 1); // Okay: topAndBottom, leftAndRight
padding(1, 1, 1, 1); // Okay: top, right, bottom, left

padding(1, 1, 1); // Error: Not a part of the available overloads

nerver 与 void

  • void 表示的是返回为空(undefined),实际上是有返回值的
  • never 是一个不包含值的类型,这意味着具有这种返回类型的函数永远不能正常返回。这意味着要么抛出异常,要么无法终止。
# void returns void, never never returns.
function do(): never {
    while (true) {}
}
const error = (msg) => throw new Error(msg); // never

const fail = () => error('failed here.'); // never
  • TypeScript
    22 引用 • 19 回帖 • 2 关注
  • 前端

    前端技术一般分为前端设计和前端开发,前端设计可以理解为网站的视觉设计,前端开发则是网站的前台代码实现,包括 HTML、CSS 以及 JavaScript 等。

    247 引用 • 1348 回帖 • 2 关注
  • 分享

    有什么新发现就分享给大家吧!

    248 引用 • 1795 回帖 • 2 关注
1 操作
Rabbitzzc 在 2020-10-27 10:52:07 更新了该帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...