void

  1. 当一个函数没有返回值时,通常会见到其返回值类型是 void

    // 无论 strictNullChecks 为 true/false,undefined 都可以赋值给 void
    // 只有 strictNullChecks 为 false,null 可以赋值 void
    function fn(): void {
      return undefined;
    }
    
  2. voidnever 的区别:

    1. void 可又被赋值为 null、undefinednever 不能包含任何类型;
    2. 返回类型为 void 的函数能还执行,但是返回 never 的函数无法正常执行 (死循环/异常终止)

Object 类型

  1. Object 类型是指除了原始类型以外的其它类型

    // object 类型是指除了原始类型以外的其它类型
    const foo: object = function () {};
    const foo1: object = [];
    const foo2: object = {};
    
  2. 如果需要明确限制对象类型,则应该使用这种 类型对象字面量 的语法,或者是 「接口」

    // 如果需要明确限制对象类型,则应该使用这种类型对象字面量的语法,或者是「接口」
    const obj: { foo: number; bar: string } = { foo: 123, bar: "string" };
    

数组类型

  1. 两种方式定义数组:

    // 第一种:使用数组泛型,Array<元素类型>:
    const arr1: Array<number> = [1, 2, 3];
    
    // 第二种:在元素类型后面接上[]:
    const arr2: number[] = [1, 2, 3];
    
  2. 案例:

    // 如果是 JS,需要判断是不是每个成员都是数字
    // 使用 TS,类型有保障,不用添加类型判断
    function sum(...args: number[]) {
      return args.reduce((prev, current) => prev + current, 0);
    }
    sum(1, 2, 3); // => 6
    

元组类型

  1. 元组类型允许表示一个 已知 元素数量类型 的数组,各元素的类型不必相同;

  2. 示例代码:

    // 元组类型:在定义数组的时候,类型和数据的个数一开始就已经限定了
    let t1: [string, number];
    
    t1 = ['hello', 10]; // OK
    t1 = [10, 'hello']; // Error
    t1.push(30);        // OK,可以 push 新增
    console.log(t1[2]); // Error,不可以访问
    

任意类型

  1. 在编程阶段还 不清楚类型的变量 指定一个类型,这种情况下,使用 any 类型直接让它们通过编译阶段的检查;

    let foo: any = "string";
    foo = 100;
    foo = true;
    
  2. 当一个数组中要存储多个数据,个数不确定,类型不确定,此时也可以使用 any 类型来定义数组,这种情况下也没有错误的提示信息,any 类型有优点,也有缺点;

    let list: any[] = [1, true, 'free']
    list[1] = 100
    

函数类型

函数声明

// 可选参数:声明的时候,内部的参数使用了 ? 进行修饰,可选参数必须在最后
// 默认参数:声明的时候,内部的参数有自己的默认值
// 剩余参数:是放在函数声明的时候所有的参数的最后
function sum(a: number, b: number = 10, ...rest: number[]): string {
  return "func1";
}
sum(100, 200);
sum(100);
sum(100, 200, 300);

函数表达式

type GetName = (firstName: string, lastName: string) => string;

let getName: GetName = function (firstName, lastName) {
  return firstName + lastName;
}

函数的重载

函数签名 = 函数名称 + 函数参数 + 函数参数类型 + 返回值类型四者合成

/**
 * 得到a*b的结果
 * @param a
 * @param b
 */
function combine(a: number, b: number): number;
/**
 * 得到a和b拼接的结果
 * @param a
 * @param b
 */
function combine(a: string, b: string): string;

function combine(a: number | string, b: number | string): number | string {
  if (typeof a === "number" && typeof b === "number") {
    return a * b;
  } else if (typeof a === "string" && typeof b === "string") {
    return a + b;
  }
  throw new Error("a 和 b 必须是相同的类型");
}

const result = combine("a", "b");

类型断言、非空断言、双重断言

  1. 通过类型断言这种方式可以告诉编译器 “相信我,我知道自己在干什么”;类型断言好比其它语言里的类型转换,但是不进行特殊的数据检查和解构,它没有运行时的影响,只是在编译阶段起作用;

  2. 示例代码:

    TypeScript
    TypeScript
    TypeScript
    // 假定这个 nums 来自一个明确的接口
    const nums = [110, 120, 119, 112];
    // 由于 ts 不确定 res 的类型
    const res = nums.find((i) => i > 0); // res: number | undefined
    
    
    // 类型断言方式一:
    const num1 = res as number;
    // 类型断言方式二:
    const num2 = <number>res; // 缺点:JSX 下不能使用
    
    let element: (HTMLElement | null) = document.getElementById('root');
    
    // 非空断言 !
    element!.style.color = 'green';
    
    let res: string | number;
    
    // 双重断言
    console.log(res! as any as boolean);
    console.log(res! as unknown as boolean);
    

any、unknown 类型

  1. any:任何类型的值可以赋值给 any,同时 any 类型的值也可以赋值给任何类型

    let a: any;
    
    a = 1;              // 通过,a 是 any 类型
    a = 'aasd';         // 通过,a 是 any 类型
    let b: number = a;  // 通过,a 是 any 类型,可以被赋值给任意类型
    
    console.log('b', b); // 打印结果是 aasd,违背了 b 的 number 类型设置,但是不会报错
    
  2. unknown:任何类型的值都可以赋值给 unknown,但 unknown 只能赋值给 unknownany 类型,所以 unknown 实际上是一个类型安全的 any

    let a: unknown;
    
    a = 1;              // 通过,unknown 类型可以被赋任意值
    a = 'aasd';         // 通过,unknown 类型可以被赋任意值
    let b: number = a;  // 报错,unknown 类型只能赋值给 any 类型和 unknown 类型
    
  3. neverunknown 的子类型

    type isNever = never extends unknown ? true : false;
    
  4. keyof unknown 等于 never

    type keys = keyof unknown;
    

联合类型

  1. 联合类型 |:指多个类型的合并类型,联合会合并子类型,最终合并成 any 类型;

    let myName: string | number;
    
    // 只能访问联合中所有共同成员
    console.log(myName!.toString());
    
    // 赋值为数字后,能访问 number 的方法
    myName = 3;
    console.log(myName.toFixed(2));
    
    // 赋值为字符串后,能访问 string 的方法
    myName = '张三';
    console.log(myName.length);
    
  2. 可辨析联合类型:可辨识要求联合类型中的每个元素都含有一个单例类型属性

    interface Square {
      kind: 'square';
      size: number;
    }
    
    interface Rectangle {
      kind: 'rectangle';
      width: number;
      height: number;
    }
    
    // 有人仅仅是添加了 `Circle` 类型,希望 TypeScript 能在任何被需要的地方抛出错误
    interface Circle {
      kind: 'circle';
      radius: number;
    }
    
    type Shape = Square | Rectangle | Circle;
    
    function area(s: Shape) {
      if (s.kind === 'square') {
        return s.size * s.size;
      } else if (s.kind === 'rectangle') {
        return s.width * s.height;
      } else {
        // Error: 'Circle' 不能被赋值给 'never',添加了 Circle 就不会报错了
        const _exhaustiveCheck: never = s;
      }
    }
    

交叉类型

  1. 交叉类型 &:多种类型的集合,交叉会向子类型收敛,最终收敛成 never 类型;

    TypeScript
    TypeScript
    interface A { name: string, c: number }
    interface B { age: number, c: number }
    
    type C = A & B;
    let c: C = { name: '张三', age: 10, c: 10 };
    
    let a: A = c; // c 是 a 的子类型
    let b: B = c; // c 是 b 的子类型
    
    type AA = string | number;
    type BB = string | boolean;
    
    type CC = AA & BB; // string,CC 是 AA、BB 的子类型
    
  2. 出现某些类型存在相同的成员,但对应的类型又不一致

    // 非对象类型交叉运算
    type N0 = string & number; // never
    type N1 = any & 1; // any
    type N2 = any & never; // never
    
    // 对象类型交叉运算
    type A = { kind: 'a', foo: string };
    type B = { kind: 'b', foo: number };
    type C = { kind: 'c', foo: number };
    type AB = A & B; // never
    type BC = B & C; // never
    
    // 函数类型交叉运算
    type A = (a: string, b: string) => void;
    type B = (a: number, b: number) => void;
    type AB = A & B
    let func: AB = (a: number | string, b: number | string) => { } 
    
  3. 案例

    // 合并两个 Object
    function mixin<T, U>(one: T, two: U) {
        const result = {} as (T & U);
    
        // 获取对象属性,强制类型 (result as T)[key]
        for (let key in one) (result as T)[key] = one[key];
        for (let key in two) (result as U)[key] = two[key];
    
        return result;
    }
    
    // 测试
    const x = mixin({ name: '张三' }, { age: 11 });
    console.log(x.name, x.age);
    

类型别名

对已知的一些类型定义名称

type Gender = "男" | "女"
type User = {
    name: string
    age: number
    gender: Gender
}

案例:创建并打印扑克牌

type Color = "♥" | "♠" | "♦" | "♣";
type NormalCard = {
    color: Color
    mark: number
}
type Deck = NormalCard[];


function createDeck(): Deck {
    const deck: Deck = [];
    for (let i = 1; i <= 13; i++) {
        deck.push({ mark: i, color: "♠" });
        deck.push({ mark: i, color: "♣" });
        deck.push({ mark: i, color: "♥" });
        deck.push({ mark: i, color: "♦" });
    }
    return deck;
}

function printDeck(deck: Deck) {
    let result = "\n";
    deck.forEach((card, i) => {
        let str = card.color;
        if (card.mark <= 10) {
            str += card.mark;
        }
        else if (card.mark === 11) {
            str += "J";
        }
        else if (card.mark === 12) {
            str += "Q";
        }
        else {
            str += "K";
        }
        result += str + "\t";
        if ((i + 1) % 4 === 0) {
            result += "\n";
        }
    })
    console.log(result);
}

const deck = createDeck();
printDeck(deck);
打赏作者
您的打赏是我前进的动力
微信
支付宝
评论

中午好👏🏻,我是 ✍🏻   疯狂 codding 中...

粽子

这有关于前端开发的技术文档和你分享。

相信你可以在这里找到对你有用的知识和教程。

了解更多

目录

  1. 1. void
  2. 2. Object 类型
  3. 3. 数组类型
  4. 4. 元组类型
  5. 5. 任意类型
  6. 6. 函数类型
    1. 6.1. 函数声明
    2. 6.2. 函数表达式
    3. 6.3. 函数的重载
  7. 7. 类型断言、非空断言、双重断言
  8. 8. any、unknown 类型
  9. 9. 联合类型
  10. 10. 交叉类型
  11. 11. 类型别名
  12. 12. 案例:创建并打印扑克牌