TypeScript技术体系

重要通知

TypeScript 是 JavaScript 的超集,扩展了 JavaScript 的语法,因此现有的 JavaScript 代码可与 TypeScript 一起工作无需任何修改,TypeScript 通过类型注解提供编译时的静态类型检查。

基本概况

安德斯·海尔斯伯格(Anders Hejlsberg),1960年12月出生于丹麦哥本哈根,曾在丹麦科技大学学习工程学,计算机科学家。Turbo Pascal编译器的主要作者,Delphi、C#和TypeScript之父,.NET(dotnet)创立者。

JavaScript与TypeScript区别

  • TS是强类型的Javascript超集,它的优势是编译阶段进行类型检查抛出异常,而JS是执行阶段遇到错误才抛出异常。
  • 编译耗时,且第三方生态需要同步支持TS。

安装配置

> pnpm install -g typescript # 安装
> tsc -v # 检查版本
> tsc --init # 制定目录初始化
> tsc --outDir ./dist test.ts # 编译单个文件
> tsc file1.ts file2.ts file3.ts # 编译多个文件

tsconfig.json

{
  // 示例
  "compilerOptions": {
    "composite": true,
    "lib": [],
    "outDir": "./dist",
    "baseUrl": "./",
    "paths": {
      "@/*": ["*", "src/*"]
    },
    "alwaysStrict": true,
    "noImplicitAny": true,
    "removeComments": true,
    "allowSyntheticDefaultImports": true,  // 允许使用 import Vue from 'vue' 这类语法

    "module": "commonjs",
    "moduleResolution": "node",
    "target": "esnext",
    "outDir": "dist",
    "strict": true,
    "pretty": true,
    "sourceMap": true,
    "strictPropertyInitialization": true,
    "strictNullChecks": true,
    "lib": [
      "es2017"
    ]
  },


  "compileOnSave": false,


  "compilerOptions": {
    "module": "es2015",                   // 指定模块是es2015的
    "moduleResolution": "node",           // 指定路径解析方式用node
    "target": "es5",                      // 指定编译后的js使用es5版本
    "lib": [
      "dom",
      "es5",
      "es2015.promise"
    ],
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"],
      "@workspace/shared": ["libs/shared/src/index.ts"]
    }
    // 严格检查的总开关
    "strict": true,
    // 编译ts出现的版本
    "target": "ESNext",
    // 模块化版本
    "module": "amd",
    // 包含的库
    "lib": ["DOM", "esnext"],
    // outDir用来指定编译后所在的目录
    "outDir": "./dist",
    // 合并文件只支持amd
    "outFile": "./dist/app.js",
    // allowJs是否对js文件进行编译,默认是false
    "allowJs": false,
    // 是否检查js语法是否符合规范,默认是false
    "checkJs": false,
    // 注释是否编译到js文件,默认false
    "removeComments": false,
    // 不生成编译后的文件
    "noEmit": false,
    // 有错误不生成编译文件
    "noEmitOnError": false,
    // 编译严格模式
    "alwaysStrict": true,
    // 不允许掩式any
    "noImplicitAny": true,
    // 不允许不明确的类型this
    "noImplicitThis": false,
    // 检查空值
    "strictNullChecks": true,
    "outDir": "./dist/",
    "sourceMap": true,
    "noImplicitAny": true,
    "module": "es6",
    "target": "es5",
    "jsx": "react"
  },
  "include": [
    "src/**/*",
    "src/**/*.ts", 
    "**/**/*.d.ts", 
    "src/**/*.vue", 
    "src/**/*.tsx"
  ],
  "exclude": [
    "node_modules",
    "**/*.spec.ts"
  ]
}

声明文件

TypeScript 作为 JavaScript 的超集,在开发过程中不可避免要引用其他第三方的 JavaScript 的库,需要将这些库里的函数和方法体去掉后只保留导出类型声明,而产生了一个描述 JavaScript 库和模块信息的声明文件。

// 声明文件以 .d.ts 为后缀
declare const count: number;
declare function greet(greeting: string): void;
declare namespace Basic {
  function makeGreeting(s: string): string;
  let numberOfGreetings: number;
}


// src/declare/images.d.ts
declare module '*.svg'
declare module '*.png'
declare module '*.jpg'
declare module '*.jpeg'
declare module '*.gif'


// src/declare/index.d.ts
declare module 'highlight.js';


// vue-shim.d.ts
declare module '*.vue' {
	import { ComponentOptions } from 'vue';
	const componentOptions: ComponentOptions;
	export default componentOptions;
}

关闭TS校验语句

// @ts-ignore # 忽视本行代码的小错误
// @ts-nocheck # 忽略全文
// @ts-check # 取消忽略全文

特别注意

对于第三方没有声明的TS规范,可以使用yarn add @type/element-plus导入TS声明

类型断言

类型断言好比其它语言里的类型转换,但是不进行特殊的数据检查和解构。

  • "尖括号"语法
let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;
  • as语法
let someValue: any = "this is a string";
let strLength: number = (someValue as string).length;

Mixins混合

Mixins混合,即在原有属性与功能的基础进行可复用性添加新的属性或功能等。

function applyMixins(derivedCtor: any, baseCtors: any[]) {
  baseCtors.forEach(baseCtor => {
    Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => {
      derivedCtor.prototype[name] = baseCtor.prototype[name];
    })
  });
}

模块与命名空间

导出语法

// 导出变量
export const 

// 导出函数

// 导出接口

// 导出命名空间

// 导出声明

代码示例

a.ts

export namespace Basic {
  export interface Vnode {
    name: string;
  }
}

b.ts

import { Basic } from './a';

function createVnode(vnode: Basic.Vnode) {
	console.log('打印');
}
createVnode({ name: '111' });

第二章 基础类型声明

变量

export const toolsList = [];
export type InitHook = (vNode: VNode) => any;

// 字符串
const title: string = "";
const titleList: String[] = [];

// 数字
const count: number = 0;
const countList: Number[] = [];

// 布尔
const close: boolean = false;
const closeList: Boolean[] = [];

// 任意类型
const student: any = {};

// 
const student: Record<string, any> = {};
const studentList: Record<string, any>[] = [];

函数

function add(x: number, y: number) {
  return x + y;
}

// 
function idModel(
  id: string | number, 
  index?: number // 可选属性
) {
  //
}

interface ClockInterface {
    currentTime: Date;
}

class Clock implements ClockInterface {
  public title: string; // 公共修饰符可以在实例化、派生类中被访问
  private sex: string; // 私有修饰符可以在内部方法中访问
  protected total: number; // 受保护修饰符可以在派生类中被访问

  static origin = {x: 0, y: 0}; // 静态属性

  currentTime: Date;

  constructor(h: number, m: number) {
    console.info(h, m)
  }

  run(name = '名称') {
    console.info(name)
  }
}

const clock = new Clock(1, 2);
clock.run();

枚举

export enum Color {Red = 1, Green = 2, Blue = 4}

类型别名


类型别名和接口的区别

几乎所有的特性interface都可以使用type,主要区别在于type不能重新打开类型来添加新属性,而接口总是可扩展的。

  • 类型别名可能不参与声明合并,但接口可以。
// interface
interface Window {
  title: string;
}

interface Window {
  ts: TypeScriptAPI;
}

const src = 'const a = "Hello World"';
window.ts.transpileModule(src, {});


// type
type Window = {
  title: string;
}

type Window = {
  ts: TypeScriptAPI;
}

// Error: Duplicate identifier 'Window'.
  • 接口只能用于声明对象的形状,不能重命名原语。

  • 接口名称将始终以其原始形式出现在错误消息中,但仅在按名称使用时才出现。

区别举例

// 扩展接口interface
interface Animal {
  name: string;
}

interface Bear extends Animal {
  honey: boolean;
}

const bear = getBear();
bear.name;
bear.honey;


// 扩展类型别名type
type Animal = {
  name: string;
}

type Bear = Animal & { 
  honey: boolean;
}

const bear = getBear();
bear.name;
bear.honey;

接口

export interface example {
  readonly name: string; // readonly修饰符只读属性必须在声明时或构造函数里被初始化。
  readonly age: number = 27;

  constructor() {
    this.name = '张三';
  }
}

interface Vnode {
  flag: number; // 数字
  name: string; // 字符串
  list: number[]; // 数组
  stack: Array<number>; // 数组泛型
  conatiner: [string, number]; // 元组 Tuple
  isMount: boolean; // 布尔值
  color: Color; // 枚举
  type: any; // Any
  run: (...args: any[]) => void; // Void
  parent: null; // Null
  root: undefined; // Undefined
  dom: never; // Never
  props: object || null; // Object,除number,string,boolean,symbol,null或undefined之外的类型。
}

class createVnode implements Vnode {
  //
}

interface Shape {
    color: string;
}

interface Square extends Shape {
    sideLength: number;
}

keyof

Object.entries(data).forEach((item: any[]) => {
  userInfo[item[0] as keyof USER_INFO] = item[1];
});

高级类型

交叉类型(Intersection Types)

交叉类型是将多个类型合并为一个类型。

function extend<T, U>(first: T, second: U): T & U {
  let result = <T & U>{};
  for (let id in first) {
    (<any>result)[id] = (<any>first)[id];
  }
  for (let id in second) {
    if (!result.hasOwnProperty(id)) {
      (<any>result)[id] = (<any>second)[id];
    }
  }
  return result;
}

联合类型(Union Types)

联合类型表示一个值可以是几种类型之一。

分流

function tsMoule(value: string | number) {
  if (typeof value === 'string') {
    //
  } else {
    //
  }
}

function stModule(value: string | string[]) {
  if (Array.isArray(value)) {
    //
  } else {
    //
  }
}

分类

interface Bird {
  fly();
  layEggs();
}
interface Fish {
  swim();
  layEggs();
}
function getSmallPet(): Fish | Bird {
  // ...
}
let pet = getSmallPet();
pet.layEggs(); // okay
pet.swim();    // errors

类型保护与区分类型

类型保护就是一些表达式,它们会在运行时检查以确保在某个作用域里的类型。

let pet = getSmallPet();

if ((<Fish>pet).swim) {
  (<Fish>pet).swim();
}
else {
  (<Bird>pet).fly();
}

function isFish(pet: Fish | Bird): pet is Fish {
  return (<Fish>pet).swim !== undefined;
}

索引类型(Index types)

使用索引类型,通过索引类型查询和索引访问操作符,编译器就能够检查使用了动态属性名的代码。

function pluck<T, K extends keyof T>(o: T, names: K[]): T[K][] {
  return names.map(n => o[n]);
}
interface Person {
  name: string;
  age: number;
}
let person: Person = {
  name: 'Jarid',
  age: 35
};
let strings: string[] = pluck(person, ['name']);

映射类型

在映射类型里,新类型以相同的形式去转换旧类型里每个属性。

type Readonly<T> = {
  readonly [P in keyof T]: T[P];
}
type Partial<T> = {
  [P in keyof T]?: T[P];
}

type PersonPartial = Partial<Person>;
type ReadonlyPerson = Readonly<Person>;

装饰器

装饰器是一种特殊类型的声明,它能够被附加到类声明,方法, 访问符,属性或参数上,可以用来修改类、方法、属性或参数的行为。

注意事项

VSCode中需要开启experimentalDecorators支持:VSCode -> Preferences -> Settings:experimentalDecorators

  • 在tsconfig.json中设置
{ 
  { 
    "compilerOptions": { 
      "target": "ES5", 
      "experimentalDecorators": true 
    } 
  }
}
  • 参数装饰器
  • 属性装饰器
  • 访问器装饰器
  • 方法装饰器
  • 类装饰器
  • 装饰器执行顺序:属性 > 方法 > 方法参数 > 类

HTMLInputElement声明

/*
React projects that don't include the DOM library need these interfaces to compile.
React Native applications use React, but there is no DOM available. The JavaScript runtime
is ES6/ES2015 only. These definitions allow such projects to compile with only `--lib ES6`.

Warning: all of these interfaces are empty. If you want type definitions for various properties
(such as HTMLInputElement.prototype.value), you need to add `--lib DOM` (via command line or tsconfig.json).
*/

interface Event { }
interface AnimationEvent extends Event { }
interface ClipboardEvent extends Event { }
interface CompositionEvent extends Event { }
interface DragEvent extends Event { }
interface FocusEvent extends Event { }
interface KeyboardEvent extends Event { }
interface MouseEvent extends Event { }
interface TouchEvent extends Event { }
interface PointerEvent extends Event { }
interface TransitionEvent extends Event { }
interface UIEvent extends Event { }
interface WheelEvent extends Event { }

interface EventTarget { }
interface Document { }
interface DataTransfer { }
interface StyleMedia { }

interface Element { }
interface DocumentFragment { }

interface HTMLElement extends Element { }
interface HTMLAnchorElement extends HTMLElement { }
interface HTMLAreaElement extends HTMLElement { }
interface HTMLAudioElement extends HTMLElement { }
interface HTMLBaseElement extends HTMLElement { }
interface HTMLBodyElement extends HTMLElement { }
interface HTMLBRElement extends HTMLElement { }
interface HTMLButtonElement extends HTMLElement { }
interface HTMLCanvasElement extends HTMLElement { }
interface HTMLDataElement extends HTMLElement { }
interface HTMLDataListElement extends HTMLElement { }
interface HTMLDialogElement extends HTMLElement { }
interface HTMLDivElement extends HTMLElement { }
interface HTMLDListElement extends HTMLElement { }
interface HTMLEmbedElement extends HTMLElement { }
interface HTMLFieldSetElement extends HTMLElement { }
interface HTMLFormElement extends HTMLElement { }
interface HTMLHeadingElement extends HTMLElement { }
interface HTMLHeadElement extends HTMLElement { }
interface HTMLHRElement extends HTMLElement { }
interface HTMLHtmlElement extends HTMLElement { }
interface HTMLIFrameElement extends HTMLElement { }
interface HTMLImageElement extends HTMLElement { }
interface HTMLInputElement extends HTMLElement { }
interface HTMLModElement extends HTMLElement { }
interface HTMLLabelElement extends HTMLElement { }
interface HTMLLegendElement extends HTMLElement { }
interface HTMLLIElement extends HTMLElement { }
interface HTMLLinkElement extends HTMLElement { }
interface HTMLMapElement extends HTMLElement { }
interface HTMLMetaElement extends HTMLElement { }
interface HTMLObjectElement extends HTMLElement { }
interface HTMLOListElement extends HTMLElement { }
interface HTMLOptGroupElement extends HTMLElement { }
interface HTMLOptionElement extends HTMLElement { }
interface HTMLParagraphElement extends HTMLElement { }
interface HTMLParamElement extends HTMLElement { }
interface HTMLPreElement extends HTMLElement { }
interface HTMLProgressElement extends HTMLElement { }
interface HTMLQuoteElement extends HTMLElement { }
interface HTMLSlotElement extends HTMLElement { }
interface HTMLScriptElement extends HTMLElement { }
interface HTMLSelectElement extends HTMLElement { }
interface HTMLSourceElement extends HTMLElement { }
interface HTMLSpanElement extends HTMLElement { }
interface HTMLStyleElement extends HTMLElement { }
interface HTMLTableElement extends HTMLElement { }
interface HTMLTableColElement extends HTMLElement { }
interface HTMLTableDataCellElement extends HTMLElement { }
interface HTMLTableHeaderCellElement extends HTMLElement { }
interface HTMLTableRowElement extends HTMLElement { }
interface HTMLTableSectionElement extends HTMLElement { }
interface HTMLTemplateElement extends HTMLElement { }
interface HTMLTextAreaElement extends HTMLElement { }
interface HTMLTitleElement extends HTMLElement { }
interface HTMLTrackElement extends HTMLElement { }
interface HTMLUListElement extends HTMLElement { }
interface HTMLVideoElement extends HTMLElement { }
interface HTMLWebViewElement extends HTMLElement { }

interface SVGElement extends Element { }
interface SVGSVGElement extends SVGElement { }
interface SVGCircleElement extends SVGElement { }
interface SVGClipPathElement extends SVGElement { }
interface SVGDefsElement extends SVGElement { }
interface SVGDescElement extends SVGElement { }
interface SVGEllipseElement extends SVGElement { }
interface SVGFEBlendElement extends SVGElement { }
interface SVGFEColorMatrixElement extends SVGElement { }
interface SVGFEComponentTransferElement extends SVGElement { }
interface SVGFECompositeElement extends SVGElement { }
interface SVGFEConvolveMatrixElement extends SVGElement { }
interface SVGFEDiffuseLightingElement extends SVGElement { }
interface SVGFEDisplacementMapElement extends SVGElement { }
interface SVGFEDistantLightElement extends SVGElement { }
interface SVGFEDropShadowElement extends SVGElement { }
interface SVGFEFloodElement extends SVGElement { }
interface SVGFEFuncAElement extends SVGElement { }
interface SVGFEFuncBElement extends SVGElement { }
interface SVGFEFuncGElement extends SVGElement { }
interface SVGFEFuncRElement extends SVGElement { }
interface SVGFEGaussianBlurElement extends SVGElement { }
interface SVGFEImageElement extends SVGElement { }
interface SVGFEMergeElement extends SVGElement { }
interface SVGFEMergeNodeElement extends SVGElement { }
interface SVGFEMorphologyElement extends SVGElement { }
interface SVGFEOffsetElement extends SVGElement { }
interface SVGFEPointLightElement extends SVGElement { }
interface SVGFESpecularLightingElement extends SVGElement { }
interface SVGFESpotLightElement extends SVGElement { }
interface SVGFETileElement extends SVGElement { }
interface SVGFETurbulenceElement extends SVGElement { }
interface SVGFilterElement extends SVGElement { }
interface SVGForeignObjectElement extends SVGElement { }
interface SVGGElement extends SVGElement { }
interface SVGImageElement extends SVGElement { }
interface SVGLineElement extends SVGElement { }
interface SVGLinearGradientElement extends SVGElement { }
interface SVGMarkerElement extends SVGElement { }
interface SVGMaskElement extends SVGElement { }
interface SVGMetadataElement extends SVGElement { }
interface SVGPathElement extends SVGElement { }
interface SVGPatternElement extends SVGElement { }
interface SVGPolygonElement extends SVGElement { }
interface SVGPolylineElement extends SVGElement { }
interface SVGRadialGradientElement extends SVGElement { }
interface SVGRectElement extends SVGElement { }
interface SVGStopElement extends SVGElement { }
interface SVGSwitchElement extends SVGElement { }
interface SVGSymbolElement extends SVGElement { }
interface SVGTextElement extends SVGElement { }
interface SVGTextPathElement extends SVGElement { }
interface SVGTSpanElement extends SVGElement { }
interface SVGUseElement extends SVGElement { }
interface SVGViewElement extends SVGElement { }

interface Text { }
interface TouchList { }
interface WebGLRenderingContext { }
interface WebGL2RenderingContext { }

TypeScript源码体系

Last Updated:
Contributors: 709992523, Eshen