Skip to content

Latest commit

 

History

History
1277 lines (939 loc) · 24.7 KB

index.mdx

File metadata and controls

1277 lines (939 loc) · 24.7 KB

import { CodeSurferLayout } from 'code-surfer'; import { Appear } from 'mdx-deck'; export { nightOwlFull as theme } from 'code-surfer/themes';

TypeScript 简明教程


TypeScript 是什么?

TypeScript 是 JavaScript + 类型声明,它可以编译成纯 JavaScript。


npx ts-lib-scripts create ts-hello-world

let isDone: boolean = fasle;

isDone = 2; // Error,不能将类型"2"分配给类型“boolean”
const decLiteral: number = 6;
const hexLiteral: number = 0xf00d;
const binaryLiteral: number = 0b1010;
const octalLiteral: number = 0o744;
let name: string = 'bob';
name = 'smith';
let list: number[] = [1, 2, 3];
let list: Array<number> = [1, 2, 3];
// 定义元祖类型
let x: [string, number];
// 初始化
x = ['hello', 10]; // OK
x = [10, 'hello']; // 错误,类型不匹配
let x: [string, number];
x = ['hello', 10]; // OK
x = [10, 'hello']; // 错误,类型不匹配

console.log(x[0].substr(1));
let x: [string, number];
x = ['hello', 10]; // OK
x = [10, 'hello']; // 错误,类型不匹配

console.log(x[0].substr(1));
let x: [string, number];
x = ['hello', 10]; // OK
x = [10, 'hello']; // 错误,类型不匹配

console.log(x[0].substr(1));
console.log(x[1].substr(1));
let x: [string, number];
x = ['hello', 10]; // OK
x = [10, 'hello']; // 错误,类型不匹配

console.log(x[0].substr(1));
console.log(x[1].substr(1));
let notSure: any = 4;
notSure = 'maybe a string instead';
notSure = false;
function fn(): void {
  console.log('这是一个函数类型声明');
}
let u: undefined = undefined;
let n: null = null;

enum Color {
  Red,
  Green,
  Blue,
}
const c: Color = Color.Green;
enum Color {
  Red = 1,
  Green,
  Blue,
}
const c: Color = Color.Green;
enum Color {
  Red = 1,
  Green = 2,
  Blue = 4,
}
const c: Color = Color.Green;
enum Color {
  Red = 1,
  Green,
  Blue,
}
let colorName: string = Color[2];

console.log(colorName);
enum Color {
  Red = 1,
  Green,
  Blue,
}
let colorName: string = Color[2];

console.log(colorName);

declare function create(o: object | null): void;

create({ prop: 0 }); // OK
create(null); // OK

create(42); // Error
create('string'); // Error
create(false); // Error
create(undefined); // Error

const someValue: any = 'this is a string';

const strLength: number = (<string>someValue).length;
const someValue: any = 'this is a string';

const strLength: number = (someValue as string).length;

以上两种类型断言的形式是等价的,至于用哪个,大部分时候看个人喜好。

但是,当在 TypeScript 里使用到 JSX 时,必须使用 as 语法形式的断言。


ts 非空断言关键字(!)

!和?是相对的,表示强制解析(也就是告诉 typescript 编译器,这里一定有值)


const element = document.querySelector('.item');

console.log(element.getBoundingClientRect());

console.log(element!.getBoundingClientRect());
const element = document.querySelector('.item');

console.log(element.getBoundingClientRect());

console.log(element!.getBoundingClientRect());

interface Props {
  userName: string;
}

function Hello(props: Props) {
  return <div>Hello, {props.userName}</div>;
}
interface SquareConfig {
  color?: string;
  width?: number;
}

function createSquare(config: SquareConfig): { color: string; area: number } {
  let newSquare = { color: 'white', area: 100 };
  if (config.color) {
    newSquare.color = config.color;
  }
  if (config.width) {
    newSquare.area = config.width * config.width;
  }
  return newSquare;
}

let mySquare = createSquare({ color: 'black' });
interface Point {
  readonly x: number;
  readonly y: number;
}
let p1: Point = { x: 10, y: 20 };

p1.x = 5; // error!
let p1: Point = { x: 10, y: 20 };

p1.x = 5; // error!

函数


function add(x, y) {
  return x + y;
}
function add(x, y) {
  return x + y;
}
function add(x: number, y: number): number {
  return x + y;
}
function add(x: number, y: number): number {
  return x + y;
}
add(1, 2); // OK
add(1, '2'); // error
add(1, 2); // OK
add(1, '2'); // error

函数类型

函数作为值传递时的类型声明。


function calc(
  x: number,
  y: number,
  calcFn: ???,
): number {
  return calcFn(x, y);
}
function calc(
  x: number,
  y: number,
  calcFn: ???,
): number {
  return calcFn(x, y);
}
function calc(
  x: number,
  y: number,
  calcFn: (x: number, y: number) => number,
): number {
  return calcFn(x, y);
}
function add(x: number, y: number): number {
  return x + y;
}

calc(1, 2, add); // ok
function pow(x: number, y: number): number {
  return x ** y;
}

calc(1, 2, pow); // ok
function divide(x: number, y: number): number {
  return x / y;
}

calc(2, 1, divide); // ok
function sum(x: number, y: number, z: number): number {
  return x + y + z;
}

calc(1, 2, sum); // error

在接口中定义函数类型的参数


interface Point {
  readonly x: number;
  readonly y: number;

  distinct(anotherPoint: Point): number;
}
interface Point {
  readonly x: number;
  readonly y: number;

  distinct(anotherPoint: Point): number;
}
interface Point {
  readonly x: number;
  readonly y: number;

  distinct: (anotherPoint: Point) => number;
}

可选的函数参数


function buildName(firstName: string, lastName?: string) {
  return firstName + lastName;
}
function buildName(firstName: string, lastName?: string) {
  return firstName + lastName;
}
buildName('Bob'); // ok
buildName('Bob', 'Alias'); // ok
buildName('Bob', 'Alias', 'Axx'); // error
function buildName(firstName?: string, lastName: string) {
  return firstName + lastName;
}
function buildName(firstName?: string, lastName: string) {
  return firstName + lastName;
}
function buildName(firstName: string | undefined, lastName: string) {
  return firstName + lastName;
}
function buildName(firstName?: string, lastName?: string) {
  return firstName + lastName;
}
function buildName(
  firstName: string | undefined,
  lastName: string | undefined,
) {
  return firstName + lastName;
}

函数参数默认值

可以为可选参数添加上默认值。这样,调用函数时,如果该函数参数为undefined,则该参数为默认值。


function buildName(firstName: string, lastName: string = 'Smith') {
  return firstName + lastName;
}

const result1 = buildName('Bob'); // OK, result1 = Bob Smith
const result2 = buildName('Bob', 'Adams'); // OK, result2 = Bob Adams


class Animal {
  name: string;

  constructor(theName: string) {
    this.name = theName;
  }

  move(distanceInMeters: number) {
    alert(this.name + 'moved' + distanceInMeters + 'm');
  }
}

const animal = new Animal('Kiki');
class Animal {
  name: string;

  constructor(theName: string) {
    this.name = theName;
  }

  move(distanceInMeters: number) {
    alert(this.name + 'moved' + distanceInMeters + 'm');
  }
}

const animal = new Animal('Kiki');
class Animal {
  name: string;

  constructor(theName: string) {
    this.name = theName;
  }

  move(distanceInMeters: number) {
    alert(this.name + 'moved' + distanceInMeters + 'm');
  }
}

const animal = new Animal('Kiki');
class Animal {
  name: string;

  constructor(theName: string) {
    this.name = theName;
  }

  move(distanceInMeters: number) {
    alert(this.name + 'moved' + distanceInMeters + 'm');
  }
}

const animal = new Animal('Kiki');

class Animal {
  public name: string;
  public constructor(theName: string) {
    this.name = theName;
  }
  public move(distanceInMeters: number) {
    alert(this.name + 'moved' + distanceInMeters + 'm');
  }
}

class Animal {
  private name: string;
  constructor(theName: string) {
    this.name = theName;
  }
}

new Animal('Cat').name; // 错误: 'name' 是私有的.

class Person {
  protected name: string;
  constructor(name: string) {
    this.name = name;
  }
}

class Employee extends Person {
  private department: string;

  constructor(name: string, department: string) {
    super(name);
    this.department = department;
  }

  public getElevatorPitch() {
    return (
      'Hello, my name is' + this.name + 'and I work in' + this.department + '.'
    );
  }
}

let howard = new Employee('Howard', 'Sales');
class Person {
  protected name: string;
  constructor(name: string) {
    this.name = name;
  }
}

class Employee extends Person {
  private department: string;

  constructor(name: string, department: string) {
    super(name);
    this.department = department;
  }

  public getElevatorPitch() {
    return (
      'Hello, my name is' + this.name + 'and I work in' + this.department + '.'
    );
  }
}

let howard = new Employee('Howard', 'Sales');
console.log(howard.getElevatorPitch());
console.log(howard.name); // 错误我们不能在 Person类外使用 name
class Person {
  protected name: string;
  constructor(name: string) {
    this.name = name;
  }
}

class Employee extends Person {
  private department: string;

  constructor(name: string, department: string) {
    super(name);
    this.department = department;
  }

  public getElevatorPitch() {
    return (
      'Hello, my name is' + this.name + 'and I work in' + this.department + '.'
    );
  }
}

let howard = new Employee('Howard', 'Sales');
console.log(howard.getElevatorPitch());
class Person {
  protected name: string;
  protected constructor(theName: string) {
    this.name = theName;
  }
}

// Employee 能够继承 Person
class Employee extends Person {
  private department: string;

  constructor(name: string, department: string) {
    super(name);
    this.department = department;
  }

  public getElevatorPitch() {
    return (
      'Hello, my name is' + this.name + 'and I work in' + this.department + '.'
    );
  }
}

let howard = new Employee('Howard', 'Sales');
let john = new Person('John'); // 错误: 'Person' 的构造函数是被保护的.

类型推论

对于能够显而易见的推断出变量类型的,TypeScript 允许我们省略类型声明,这就是类型推论


let x: number = 0;

x = 1; // OK
x = '1'; // error
let x = 0;

x = 1; // OK
x = '1'; // error
const x = [0, 1, null];
const zoo = [new Rhino(), new Elephant(), new Snake()];

<button
  onClick={(event) => {
    console.log(event);
  }}
>
  点击我
</button>;
const x = [0, 1, null];
const zoo = [new Rhino(), new Elephant(), new Snake()];

<button
  onClick={(event) => {
    console.log(event);
  }}
>
  点击我
</button>;
const x = [0, 1, null];
const zoo = [new Rhino(), new Elephant(), new Snake()];

<button
  onClick={(event) => {
    console.log(event);
  }}
>
  点击我
</button>;
const x = [0, 1, null];
const zoo = [new Rhino(), new Elephant(), new Snake()];

<button
  onClick={(event) => {
    console.log(event);
  }}
>
  点击我
</button>;

泛型

类型参数化。
const items: Array<number> = [1, 2, 3];
const names: Array<string> = ['张三', '李四', '王五'];
const items: Array<number> = [1, 2, 3];
const names: Array<string> = ['张三', '李四', '王五'];
const items: Array<number> = [1, 2, 3];
const names: Array<string> = ['张三', '李四', '王五'];
const items: Array<number> = [1, 2, 3];
const names: Array<string> = ['张三', '李四', '王五'];
const items: Array<number> = [1, 2, 3];
const names: Array<string> = ['张三', '李四', '王五'];

声明类型变量


function createArray(length: number, value: any): any[] {
  return new Array(length).fill(value);
}
function createArray(length: number, value: any): any[] {
  return new Array(length).fill(value);
}
function createArray(length: number, value: string): string[] {
  return new Array(length).fill(value);
}
function createArray(length: number, value: boolean): boolean[] {
  return new Array(length).fill(value);
}
function createArray(length: number, value: Date): Date[] {
  return new Array(length).fill(value);
}
function createArray(length: number, value: T): T[] {
  return new Array(length).fill(value);
}
function createArray(length: number, value: T): T[] {
  return new Array(length).fill(value);
}
function createArray<T>(length: number, value: T): T[] {
  return new Array(length).fill(value);
}
function createArray<T>(length: number, value: T): T[] {
  return new Array(length).fill(value);
}

给类型变量赋“值”

调用泛型函数,需要给类型变量赋“值”

这个“值”指类型,而非像1, '2', true这样的真实值


const items = createArray<number>(3, 1);
const strs = createArray<string>(3, '');
const items = createArray<number>(3, 1);
const strs = createArray<string>(3, '');
const items = createArray<number>(3, 1);
const strs = createArray<string>(3, '');

泛型的类型推论


const items = createArray<number>(3, 1);
const strs = createArray<string>(3, '');
const items = createArray<number>(3, 1);
const strs = createArray<string>(3, '');
const items = createArray<number>(3, 1);
const strs = createArray<string>(3, '');
const items = createArray(3, 1);
const strs = createArray<string>(3, '');
const items = createArray(3, 1);
const strs = createArray<string>(3, '');
const items = createArray(3, 1);
const strs = createArray(3, '');

泛型接口


interface List<T> {
  length: number;
  items: T[];
  get(index: number): T;
}

const items: List<number> = {
  length: 3,
  items: [1, 2, 3],
  get(index: number) {
    return this.items[index];
  },
};

class List<T> {
  public items: T[];

  public constructor(items: T[]) {
    this.items = items;
  }

  public get length() {
    return this.items.length;
  }

  public getItem(index: number): T {
    return this.items[index];
  }
}

const items = new List<number>([1, 2, 3]);
class List<T> {
  public items: T[];

  public constructor(items: T[]) {
    this.items = items;
  }

  public get length() {
    return this.items.length;
  }

  public getItem(index: number): T {
    return this.items[index];
  }
}

const items = new List<number>([1, 2, 3]);
class List<T> {
  public items: T[];

  public constructor(items: T[]) {
    this.items = items;
  }

  public get length() {
    return this.items.length;
  }

  public getItem(index: number): T {
    return this.items[index];
  }
}

const items = new List<number>([1, 2, 3]);
class List<T> {
  public items: T[];

  public constructor(items: T[]) {
    this.items = items;
  }

  public get length() {
    return this.items.length;
  }

  public getItem(index: number): T {
    return this.items[index];
  }
}

const items = new List([1, 2, 3]);

泛型约束

规定泛型必须遵循的规则。

使用extends关键字添加泛型约束。


interface Lengthwise {
  length: number;
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
  console.log(arg.length); // ok
  return arg;
}
interface Lengthwise {
  length: number;
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
  console.log(arg.length); // ok
  return arg;
}
interface Lengthwise {
  length: number;
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
  console.log(arg.length); // ok
  return arg;
}
loggingIdentity(3); // error

loggingIdentity({ length: 10, value: 3 }); // OK

泛型参数默认值

通过<T = 默认类型>为泛型指定默认的类型


function getItemElements<T extends Element = HTMLDivElement>(): NodeListOf<T> {
  return document.querySelectorAll<T>('.item');
}

高级类型


类型别名

type AnotherTypeName = string | number | null


相交类型

T0 = T1 & T2 ===> T0既是T1又是T2

T0 = T1 & T2 ===> T0包含所有T1和T2定义的属性


// 二维点
interface Point {
  readonly x: number;
  readonly y: number;
}

// 第三维度坐标
interface ZCoordinate {
  readonly z: number;
}

// 三维点
type ThreeDimensionalPoint = Point & ZCoordinate;

/*
ThreeDimensionalPoint相当于:

{
  readonly x: number;
  readonly y: number;
  readonly z: number;
}
*/

联合类型

T0 = T1 | T2 | T3 ===> T0只能是T1、T2、T3三者之一


let item: string | number | undefined;

item = '1'; // OK
item = undefined; // OK
item = 1; // OK
item = false; // error
item = null; // error

谢谢!!!!

👏👏👏

🎉🎉🎉