微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

TypeScript笔记本

  1. TypeScript for Java/C# Programmers
  2. The TypeScript Handbook
  3. C#转typescript实战
  1. ts没有静态类,也没有单例
  2. 对象赋值:
interface Pointlike {
  x: number;
  y: number;
}
interface Named {
  name: string;
}

function printPoint(point: Pointlike) {
  console.log("x = " + point.x + ", y = " + point.y);
}

function printName(x: Named) {
  console.log("Hello, " + x.name);
}

const obj = {
  x: 0,
  y: 0,
  name: "Origin",
};

printPoint(obj);
printName(obj);

obj里包含了Pointlike定义的x和y字段,所以printPoint不会报错。同理printName也不会报错。
同理下述也不会报错:

class Car {
  drive() {
    // hit the gas
  }
}
class Golfer {
  drive() {
    // hit the ball far
  }
}

// No error?
let w: Car = new Golfer();
  1. ts没有反射,但是js的typeofinstanceof,仍然能获取到对象的类型,不过都是object类型。

1. 支持的类型

ts类型(小写)C#类型说明
booleanbool
numberint和float
bigintlong
string(“或’)string
‘[]’(数组)等同[]
ArrayList或int[]
TupleTuple
enumenum
unkNowndynamicdynamic的精简版
anydynamic
voidvoid主要用在函数上,并不是很有用
null和undefinednull ???handbook说没啥用,是void的子类型
never??是其他所有类型的子类型,标识异常或死循环等
object???非基础类型,除number,stiring,boolean,symbol,null,undefined之外的类型
(function type)委托见示例

示例:

let fullName:string ='Bob';
let age:number=37;
let height:bigint=666;
let sentense:string = 'hello,my ${fullName}';//也支持插值显示
//1.数组
let list:number[]=[1,2,3];
let list:Array<number>=[1,2,3];
//2.元组
let x:[string,number];
x=['hello',2];//correct
x=['hello','sss'];//error
通过索引访问,如x[0]代表第1个元素,x[2]则报错.

//3枚举
enum Color{
    red,
    green,
    black
}
let c:Color=Color.red;
//4. unkNown 编写代码时不知道是个啥类型,C# dynamic的精简版,可以随便赋值,但是不能访问所属类型的方法。

//5. void
function wareUser():void{};
let unusable:void=undefined;

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

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

create(42);
Argument of type '42' is not assignable to parameter of type 'object | null'.
create("string");
Argument of type '"string"' is not assignable to parameter of type 'object | null'.
create(false);
Argument of type 'false' is not assignable to parameter of type 'object | null'.
create(undefined);
Argument of type 'undefined' is not assignable to parameter of type 'object | null'.

//7. function type
let myAdd: (baseValue: number, increment: number) => number =function(x:number,y:number):number{return 4;}
1.1 类型转换
let someValue: unkNown = "this is a string";

let strLength: number = (someValue as string).length;//推荐
let strLength: number = (<string>someValue).length;
1.2 var let const

https://www.typescriptlang.org/docs/handbook/variable-declarations.html

最好不要使用var,const是let的一个扩充,不允许被再次赋值。

  • var:在哪里都可以被访问,(containing function, module, namespace, or global scope - all which we’ll go over later on - regardless of the containing block)。并且可以被重复声明,不报错。如下,定义了两个i:
function sumMatrix(matrix: number[][]) {
  var sum = 0;
  for (var i = 0; i < matrix.length; i++) {
    var currentRow = matrix[i];
    for (var i = 0; i < currentRow.length; i++) {
      sum += currentRow[i];
    }
  }

  return sum;
}

即使声明了一百次,但指向同一个

  • let的作用域只限定在大括号内。在用之前必须先声明。但是也可以有以下写法,shadowing功能,最好别用:
function sumMatrix(matrix: number[][]) {
  let sum = 0;
  for (let i = 0; i < matrix.length; i++) {
    var currentRow = matrix[i];
    for (let i = 0; i < currentRow.length; i++) {
      sum += currentRow[i];
    }
  }

  return sum;
}
  • const是let的不可修改版本,但是const修饰对象时,仍然可以更改对象的某些字段。(解决方法是使用ts的readonly,二者区别时readonly修饰字段,const修饰变量)
1.3解构

https://www.typescriptlang.org/docs/handbook/variable-declarations.html#destructuring

2.接口

https://www.typescriptlang.org/docs/handbook/interfaces.html

2.1接口用来约束
interface LabeledValue {
  label: string;
  color?:string;//可选字段,即myObj里不包含这个字段也不会报错
}

function printLabel(labeledobj: LabeledValue) {
  console.log(labeledobj.label);
}

let myObj = { size: 10, label: "Size 10 Object" };
printLabel(myObj);

只读字段:

interface Point {
  readonly x: number;
  readonly y: number;
}
let p1: Point = { x: 10, y: 20 };//只有创建时可被赋值
p1.x = 5; // error! Cannot assign to 'x' because it is a read-only property.

只读的ReadonlyArray:

let a: number[] = [1, 2, 3, 4];
let ro: ReadonlyArray<number> = a;

ro[0] = 12; // error! Index signature in type 'readonly number[]' only permits reading.
ro.push(5); // error! Property 'push' does not exist on type 'readonly number[]'.
ro.length = 100; // error! Cannot assign to 'length' because it is a read-only property.
a = ro; // error! The type 'readonly number[]' is 'readonly' and cannot be assigned to the mutable type 'number[]'.
a = ro as number[];//正确

2.1.1额外的字段检查
interface SquareConfig {
  color?: string|number;
  width?: number;
}

function createSquare(config: SquareConfig): { color: string; area: number } {
  return { color: config.color || "red", area: config.width ? config.width*config.width : 20 };
}

let mySquare = createSquare({ colour: "red", width: 100 });//这么写是不对的
let obj={ colour: "red", width: 100 };
createSquare(obj);//这么写可以
let mySquare = createSquare({ width: 100, opacity: 0.5 } as SquareConfig);//这么写也可以

但是这么写又是不对的:

let obj={ colour: "red", widthsssssssss: 100 };
createSquare(obj);//error
2.1.2 函数类型 Function Types
interface SearchFunc {
  (source: string, subString: string): boolean;
}

let mySearch: SearchFunc;

mySearch = function (src: string, sub: string): boolean {
  let result = src.search(sub);
  return result > -1;
};

用接口定义方法的规范

2.2接口用来实现implements
interface ClockInterface {
  currentTime: Date;
  setTime(d: Date): void;
}

class Clock implements ClockInterface {
  currentTime: Date = new Date();
  setTime(d: Date) {
    this.currentTime = d;
  }
  constructor(h: number, m: number) {}
}
interface Shape {
  color: string;
}

interface Penstroke {
  penWidth: number;
}

interface Square extends Shape, Penstroke {
  sideLength: number;
}

let square = {} as Square;
square.color = "blue";
square.sideLength = 10;
square.penWidth = 5.0;

可以用let a= {} as Square来new对象?

混合类型Hybrid Types

interface Counter {
  (start: number): string;
  interval: number;
  reset(): void;
}

function getCounter(): Counter {
  let counter = function (start: number) {} as Counter;
  counter.interval = 123;
  counter.reset = function () {};
  return counter;
}

let c = getCounter();
c(10);
c.reset();
c.interval = 5.0;
2.3接口扩展某个类extends
class Control {
  private state: any;
}

interface SelectableControl extends Control {
  select(): void;
}

class Button extends Control implements SelectableControl {
  select() {}
}

class TextBox extends Control {
  select() {}
}

class ImageControl implements SelectableControl {
Class 'ImageControl' incorrectly implements interface 'SelectableControl'.
  Types have separate declarations of a private property 'state'.
  private state: any;
  select() {}
}

那这个接口只能被这个类的子类实现。

2.Functions (方法)

https://www.typescriptlang.org/docs/handbook/functions.html

JS的写法
// 有名字的方法
function add(x, y) {
  return x + y;
}

// 匿名方法
let myAdd = function (x, y) {
  return x + y;
};

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

let myAdd = function (x: number, y: number): number {
  return x + y;
};

2.1可空参数和参数认值

function buildName(firstName: string, lastName?: string) {
  // ...
}
function buildName(firstName: string, lastName = "Smith") {
  // ...
}
function buildName(firstName = "Will", lastName: string) {
  return firstName + " " + lastName;
}
let result4 = buildName(undefined, "Adams"); // 都是string类型,不需要的话就手动设置为undefined

2.2可变参数

类似于C#的 params

function buildName(firstName: string, ...restOfName: string[]) {
  return firstName + " " + restOfName.join(" ");
}

// employeeName will be "Joseph Samuel Lucas MacKinzie"
let employeeName = buildName("Joseph", "Samuel", "Lucas", "MacKinzie");

2.3This问题

  1. Understanding JavaScript Function Invocation and “this”
  2. Handbook
  • JS中的this指向的是调用
//会报错
let deck = {
  suits: ["hearts", "spades", "clubs", "diamonds"],
  cards: Array(52),
  createCardPicker: function () {
    return function () {
      let pickedCard = Math.floor(Math.random() * 52);
      let pickedSuit = Math.floor(pickedCard / 13);

      return { suit: this.suits[pickedSuit], card: pickedCard % 13 };
    };
  },
};

let cardPicker = deck.createCardPicker();
let pickedCard = cardPicker();

alert("card: " + pickedCard.card + " of " + pickedCard.suit);

调用方在let pickedCard = cardPicker();,而这里没有在任何方法中,所以this指向的是window,在严格模式下this会是undefined。

解决方法是使用箭头函数:ECMAScript 6:Arrow functions capture the this where the function is created rather than where it is invoked

createCardPicker: function () {
    // NOTE: the line below is Now an arrow function, allowing us to capture 'this' right here
    return () => {
      let pickedCard = Math.floor(Math.random() * 52);
      let pickedSuit = Math.floor(pickedCard / 13);

      return { suit: this.suits[pickedSuit], card: pickedCard % 13 };
    };
  },

但是使用--noImplicitThis进行编译时还会有问题,this是any,因为它来自对象内部的函数表达式。改为这样:

 createCardPicker: function (this: Deck) {
    return () => {
      let pickedCard = Math.floor(Math.random() * 52);
      let pickedSuit = Math.floor(pickedCard / 13);

      return { suit: this.suits[pickedSuit], card: pickedCard % 13 };
    };
  },

现在ts就知道this是Deck类型了。下述写法表示this不能在方法中被使用:

function f(this: void) {
  // make sure `this` is unusable in this standalone function
}

2.4重载

let suits = ["hearts", "spades", "clubs", "diamonds"];

function pickCard(x: { suit: string; card: number }[]): number;
function pickCard(x: number): { suit: string; card: number };
function pickCard(x: any): any {
  // Check to see if we're working with an object/array
  // if so, they gave us the deck and we'll pick the card
  if (typeof x == "object") {
    let pickedCard = Math.floor(Math.random() * x.length);
    return pickedCard;
  }
  // Otherwise just let them pick the card
  else if (typeof x == "number") {
    let pickedSuit = Math.floor(x / 13);
    return { suit: suits[pickedSuit], card: x % 13 };
  }
}

let myDeck = [
  { suit: "diamonds", card: 2 },
  { suit: "spades", card: 10 },
  { suit: "hearts", card: 4 },
];

let pickedCard1 = myDeck[pickCard(myDeck)];
alert("card: " + pickedCard1.card + " of " + pickedCard1.suit);

let pickedCard2 = pickCard(15);
alert("card: " + pickedCard2.card + " of " + pickedCard2.suit);

let pickedCard2 = pickCard(true);//将报错 因为只接收array和number

3.Unions and Intersection Types

联合类型(交集类型)

let a:number;//atomic type
let a:number|boolean;//这就是union type

type t=|number|boolean;
let a:t;//a属于t类型中的某一种

并集类型(Intersection Types)

interface ErrorHandling {
  success: boolean;
  error?: { message: string };
}

interface ArtworksData {
  artworks: { title: string }[];
}

interface ArtistsData {
  artists: { name: string }[];
}

// These interfaces are composed to have
// consistent error handling, and their own data.

type ArtworksResponse = ArtworksData & ErrorHandling;
type ArtistsResponse = ArtistsData & ErrorHandling;

const handleArtistsResponse = (response: ArtistsResponse) => {
  if (response.error) {
    console.error(response.error.message);
    return;
  }

  console.log(response.artists);
};

4. 类 Class

https://www.typescriptlang.org/docs/handbook/classes.html#classes

let p=new Person("name");//new一个对象
class Man extends Person{};//继承

同样也有多态

let p:Person=new Man();

同样也支持public(认)、private、protected

ECMAScript也有private,写法是#name:string,ts写法是private name :string效果是一样的。

ts属于结构型系统(structural type system),比较两个对象a和b的type是否一致时,比较的是a和b的内部成员的生命是否都一样。但是当成员里有private 和 protected的时候,就不能这么简单比较了:

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

class Rhino extends Animal {
  constructor() {
    super("Rhino");
  }
}

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

let animal = new Animal("Goat");
let rhino = new Rhino();
let employee = new Employee("Bob");

animal = rhino;//正确:因为共享同一个name
animal = employee;//错误:虽然都有name,但不是同一个

当protected修饰构造函数时,表示此类只能在子类内构造:

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

// Employee can extend 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");//错误

只读readonly:同C#,声明或者构造函数时赋值

构造参数上添加public、private、readonly:这样整个类中可直接使用,避免多一次定义

class Octopus {
  readonly numberOfLegs: number = 8;
  constructor(readonly name: string) {}
}

let dad = new Octopus("Man with the 8 strong legs");
dad.name;

给字段添加get set:set或get时做一些额外的处理,等同于C#的属性

const fullNameMaxLength = 10;

class Employee {
  private _fullName: string = "";

  get fullName(): string {
    return this._fullName;
  }

  set fullName(newName: string) {
    if (newName && newName.length > fullNameMaxLength) {
      throw new Error("fullName has a max length of " + fullNameMaxLength);
    }

    this._fullName = newName;
  }
}

let employee = new Employee();
employee.fullName = "Bob Smith";

if (employee.fullName) {
  console.log(employee.fullName);
}

静态字段Static:同C#的static

抽象类Abstract:同C#的抽象类,子类不需要有override修饰。

5.枚举

enum Direction {
  Up=1,//不指定的话,认为0.
  Down,
  Left,
  Right
}

枚举的赋值可以为number或string类型。

枚举的值也可以通过计算赋值:

enum FileAccess {
  G = "123".length
}

6.泛型Generics

https://www.typescriptlang.org/docs/handbook/generics.html

同C#的泛型

泛型约束
如果要约束泛型的类型:

interface Lengthwise {
  length: number;
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
  console.log(arg.length); // Now we kNow it has a .length property, so no more error
  return arg;
}

(T extends Lenghtwise就等同于C#的 where T: Lengthwise.

同理还有K extends keyof T:K需要是T里面的一个key。

可以被new:

function create<T>(c: { new (): T }): T {
  return new c();
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐