TypeScript 类型校验

74 阅读2分钟

基础的类型校验

函数输入参数校验

  • 输入参数为string
// 函数输入参数校验
function greet(name: string) {
    console.log("Hello, " + name.toUpperCase() + "!!");
}

greet('43');
  • 输入参数为object
// Object Types
function printCoord(pt: { x: number; y: number }) {
    console.log("The coordinate's x value is " + pt.x);
    console.log("The coordinate's y value is " + pt.y);
}
printCoord({ x: 3, y: 7 });
  • 输入参数可选
// Optional Properties
function printName(obj: { first: string; last?: string }) {
    // ...
}
  • 联合参数
// Union Types
function printId(id: number | string) {
    console.log("Your ID is: " + id);
}
  • 定义type
// Type Aliases
type Point = {
    x: number;
    y: number;
};

function printCoord2(pt: Point) {
    console.log("The coordinate's x value is " + pt.x);
    console.log("The coordinate's y value is " + pt.y);
}

printCoord2({ x: 100, y: 100 });
  • 定义Interfaces
// Interfaces
interface Point2 {
    x: number;
    y: number;
}

function printCoord3(pt: Point2) {
    console.log("The coordinate's x value is " + pt.x);
    console.log("The coordinate's y value is " + pt.y);
}

printCoord3({ x: 100, y: 100 });
  • 定义Assertions
// Type Assertions
const myCanvas = <HTMLCanvasElement>document.getElementById("main_canvas");
  • 定义Literal Types
// Literal Types
function printText(s: string, alignment: "left" | "right" | "center") {
    // ...
}
printText("Hello, world", "left");

函数返回值校验

// Return Type Annotations
function getFavoriteNumber(): number {
    return 26;
}

类的继承

// Class Heritage
// implements Clauses

interface Pingable {
    ping(): void;
}

class Sonar implements Pingable {
    ping() {
        console.log("ping!");
    }
}

//  declare key word
declare resident: Dog;

函数

输入参数为函数时的类型校验

  • 直接型
// Function Type Expressions
function greeter(fn: (a: string) => void) {
    fn("Hello, World");
}

// use alias
type GreetFunction = (a: string) => void;
function greeter1(fn: GreetFunction) {
    // ...
}
  • 定义签名型
// Call Signatures
type DescribableFunction = {
    description: string;
    (someArg: number): boolean;
};
function doSomething(fn: DescribableFunction) {
    console.log(fn.description + " returned " + fn(6));
}

// Construct Signatures
type SomeObject = {}
type SomeConstructor = {
    new (s: string): SomeObject;
};
function fn(ctor: SomeConstructor) {
    return new ctor("hello");
}

泛型函数

// Generic Functions
function firstElement<Type>(arr: Type[]): Type | undefined {
    return arr[0];
}

// Inference
function map<Input, Output>(arr: Input[], func: (arg: Input) => Output): Output[] {
    return arr.map(func);
}
// Parameter 'n' is of type 'string'
// 'parsed' is of type 'number[]'
const parsed = map(["1", "2", "3"], (n) => parseInt(n));

约束

// Constraints
function longest<Type extends { length: number }>(a: Type, b: Type) {
    if (a.length >= b.length) {
        return a;
    } else {
        return b;
    }
}

// Specifying Type Arguments
function combine<Type>(arr1: Type[], arr2: Type[]): Type[] {
    return arr1.concat(arr2);
}
const arr = combine<string | number>([1, 2, 3], ["hello"]);

// Optional Parameters
function f(x?: number) {
    // ...
}
f(); // OK
f(10); // OK

模块

ES 模块

// TypeScript Specific ES Module Syntax

// example 1
// @filename: animal.ts
export type Cat = { breed: string; yearOfBirth: number };

export interface Dog {
    breeds: string[];
    yearOfBirth: number;
}

// @filename: app.ts
import { Cat, Dog } from "./animal.js";
type Animals = Cat | Dog;

CommonJS 模块

// example 2
// @filename: animal.ts
import type { Cat1, Dog2 } from "./animal.js";

// CommonJS Syntax
function absolute(num: number) {
    if (num < 0) return num * -1;
    return num;
}

module.exports = {
    pi: 3.14,
    squareTwo: 1.41,
    phi: 1.61,
    absolute,
};

const maths = require("maths");
maths.pi;

对象

基础的Object类型校验

  • 可选参数
// Optional Properties
interface PaintOptions {
    shape: String;
    xPos?: number;
    yPos?: number;
}
  • readonly
// readonly Properties  It just means the property itself can’t be re-written to.
interface SomeType {
    readonly prop: string;
}

function doSomething(obj: SomeType) {
    // We can read from 'obj.prop'.
    console.log(`prop has the value '${obj.prop}'.`);

    // But we can't re-assign it.
    obj.prop = "hello"; //Cannot assign to 'prop' because it is a read-only property.
}
  • Index签名
// Index Signatures
interface StringArray {
    [index: number]: string;
}

扩展的Object类型校验

  • 扩展类型

// Extending Types
interface BasicAddress {
    name?: string;
    street: string;
    city: string;
    country: string;
    postalCode: string;
}

interface AddressWithUnit extends BasicAddress {
    unit: string;
}
  • Intersection 类型
// Intersection Types
interface Colorful {
    color: string;
}
interface Circle {
    radius: number;
}

type ColorfulCircle = Colorful & Circle;
  • 对象泛型
// Generic Object Types
interface Box<Type> {
    contents: Type;
}
let box: Box<string>;
  • 数组类型
// The Array Type
function doSomething1(value: Array<string>) {
    // ...
}

let myArray1: string[] = ["hello", "world"];
// either of these work!
doSomething1(myArray1);
doSomething1(new Array("hello", "world"));
  • 元组类型
// Tuple Types
type StringNumberPair = [string, number];
function doSomething2(pair: StringNumberPair) {
    const a = pair[0];
    const b = pair[1];
}

doSomething2(["hello", 42]);

// readonly Tuple Types
function doSomething3(pair: readonly [string, number]) {
    // ...
}

Type

泛型 Types

  • 通用泛型
// Type Manipulation

// 1.Generic Types
function identity<Type>(arg: Type): Type {
    return arg;
}

let myIdentity: <Type>(arg: Type) => Type = identity;
  • 泛型约束
// Generic Constraints
interface Lengthwise {
    length: number;
}

function loggingIdentity<Type extends Lengthwise>(arg: Type): Type {
    console.log(arg.length); // Now we know it has a .length property, so no more error
    return arg;
}
  • 在泛型约束使用Type参数
// Using Type Parameters in Generic Constraints
function getProperty<Type, Key extends keyof Type>(obj: Type, key: Key) {
    return obj[key];
}

let x = { a: 1, b: 2, c: 3, d: 4 };

getProperty(x, "a");
getProperty(x, "m");
  • Keyof and Typeof
// 2.Keyof Type Operator
type Point = { x: number; y: number };
type P = keyof Point; // type P is the same type as “x” | “y”:

// 3.Typeof Type Operator
let s = "hello";
let n: typeof s; // let n: string
  • Indexed Access Types
// 4.Indexed Access Types
type Person = { age: number; name: string; alive: boolean };
type Age = Person["age"]; 
// type Age = number

type I1 = Person["age" | "name"]; 
// type I1 = string | number

type I2 = Person[keyof Person]; 
// type I2 = string | number | boolean

type AliveOrName = "alive" | "name";
type I3 = Person[AliveOrName]; 
//type I3 = string | boolean

条件 Types

  • SomeType extends OtherType ? TrueType : FalseType;
// 5.Conditional Types
// SomeType extends OtherType ? TrueType : FalseType;
// example 1
interface Animal {
    live(): void;
}
interface Dog extends Animal {
    woof(): void;
}

type Example1 = Dog extends Animal ? number : string;  // type Example1 = number

// example 2
type MessageOf<T> = T extends { message: unknown } ? T["message"] : never;

interface Email {
    message: string;
}

interface Dog {
    bark(): void;
}

type EmailMessageContents = MessageOf<Email>; //type EmailMessageContents = string

type DogMessageContents = MessageOf<Dog>; // type DogMessageContents = never
  • Inferring Within Conditional Types
// 5.Conditional Types
// Inferring Within Conditional Types
type GetReturnType<Type> = Type extends (...args: never[]) => infer Return
    ? Return
    : never;

type Num = GetReturnType<() => number>; // type Num = number
type Str = GetReturnType<(x: string) => string>; // type Str = string
type Bools = GetReturnType<(a: boolean, b: boolean) => boolean[]>; // type Bools = boolean[]
  • Distributive Conditional Types
// 5.Conditional Types
// Distributive Conditional Types
type ToArrayNonDist<Type> = [Type] extends [any] ? Type[] : never;

// 'StrArrOrNumArr' is no longer a union.
type StrArrOrNumArr = ToArrayNonDist<string | number>; 
// type StrArrOrNumArr = (string | number)[]

Map Types

  • 示例1: 移除 readonly 属性
// 6.Mapped Types
// Removes 'readonly' attributes from a type's properties
// example 1
type CreateMutable<Type> = {
    -readonly [Property in keyof Type]: Type[Property];
};

type LockedAccount = {
    readonly id: string;
    readonly name: string;
};

type UnlockedAccount = CreateMutable<LockedAccount>;

// type UnlockedAccount = {
//     id: string;
//     name: string;
// }
  • 示例2: 移除 optional 属性
// example 2
// Removes 'optional' attributes from a type's properties
type Concrete<Type> = {
    [Property in keyof Type]-?: Type[Property];
};

type MaybeUser = {
    id: string;
    name?: string;
    age?: number;
};

type User = Concrete<MaybeUser>;

// type User = {
//     id: string;
//     name: string;
//     age: number;
// }
  • 示例:Remapping
// Key Remapping via as
// example 1
type MappedTypeWithNewProperties<Type> = {
    [Properties in keyof Type as NewKeyType]: Type[Properties]
}

type Getters<Type> = {
    [Property in keyof Type as `get${Capitalize<string & Property>}`]: () => Type[Property]
};

interface Person1 {
    name: string;
    age: number;
    location: string;
}

type LazyPerson = Getters<Person1>;

// type LazyPerson = {
//     getName: () => string;
//     getAge: () => number;
//     getLocation: () => string;
// }

// example 2
type EventConfig<Events extends { kind: string }> = {
    [E in Events as E["kind"]]: (event: E) => void;
}

type SquareEvent = { kind: "square", x: number, y: number };
type CircleEvent = { kind: "circle", radius: number };

type Config = EventConfig<SquareEvent | CircleEvent>

// type Config = {
//     square: (event: SquareEvent) => void;
//     circle: (event: CircleEvent) => void;
// }

Literal Types

// 7.Template Literal Types
// example 1
type Greeting = "Hello, world"
type ShoutyGreeting = Uppercase<Greeting>
//type ShoutyGreeting = "HELLO, WORLD"

// example 2
type Greeting2 = "Hello, world"
type QuietGreeting = Lowercase<Greeting2> 
//type QuietGreeting = "hello, world"

// example 3
// Capitalize<StringType>
// Converts the first character in the string to an uppercase equivalent.
type LowercaseGreeting = "hello, world";
type Greeting3 = Capitalize<LowercaseGreeting>; 
//type Greeting3 = "Hello, world"

// example 4
// Uncapitalize<StringType>
// Converts the first character in the string to a lowercase equivalent.

type UppercaseGreeting = "HELLO WORLD";
type UncomfortableGreeting = Uncapitalize<UppercaseGreeting>; 
// type UncomfortableGreeting = "hELLO WORLD"