Typescript learning essay

Basic types: string, boolean, number, null, undefined, void, never, enum, unknown, any, object, array, tuple. (null, undefined is a subtype of any type)

enum Color {R = 0, G = 1, B = 2}
let a: string | number | boolean | void | never | unknown | any | string[] | object | [string, number] | Color
a = null
a = undefined

One of the core principles of TypeScript: type checking focuses on the shape of values (based on structural types rather than nominal types); And shape matching only requires subset matching of object fields:

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

function printPoint(p: Point) {
  console.log(`${p.x}, ${p.y}`);
}

const point1 = { x: 1, y: 2 };
const point2 = { x: 1, y: 2, z: 3 };
printPoint(point1);
printPoint(point2);

Note: in general, subsets are OK. However, if the object literal is allocated to other variables or passed as parameters, it will be subject to special processing and excessive Property Checks. If the object literal has any attribute that the target type does not have, an error will occur; Type assertion / index signature can be used to deal with this situation, as follows:

Type assertions need to be developed to ensure that their parameters are correct:

function printA(o: { a: string }) {
  console.log(o.a);
}

let myObj = { a: "a", b: 1 };
printA(myObj); // normal
printA({ a: "a", b: 1 }); // Argument of type '{ a: string; b: number; }' is not assignable to parameter of type '{ a: string; }'.
printA(<{ a: string }>{ a: "a", b: 1 }); // normal

let o: { a: string };
o = { a: 'a' }; // normal
o = { a: 'a', b: 1 }; // Type '{ a: string; b: number; }' is not assignable to type '{ a: string; }'.
o = { a: 'a', b: 1 } as { a: string }; // normal

The attribute of the index in the index signature must be a superset of other attributes:

interface Test {
  testA: string;
  testB: number;
  [propName: string]: string | number;
}

 

function printA(o: { a: string, [propName: string]: any }) {
  console.log(o.a);
}

let myObj = { a: "a", b: 1 };
printA(myObj); // normal
printA({ a: "a", b: 1 }); // normal

let o: { a: string, [propName: string]: any };
o = { a: 'a' }; // normal
o = { a: 'a', b: 1 }; // normal

Two types of index signatures are supported: string and number. Both types of indexers can be supported, but the type returned from the numeric indexer must be a subtype of the type returned from the string indexer. This is because when you index with number, JavaScript actually converts it to a string before it is indexed into an object. This means that index 100(number) and index "100"(string) are the same thing, so the two should be consistent.

interface Animal {
  name: string;
}

interface Dog extends Animal {
  breed: string;
}

interface NotOkay {
  [x: number]: Animal; // Numeric index type 'Animal' is not assignable to string index type 'Dog'.
  [x: string]: Dog;
}

interface Okay {
  [x: number]: Dog; // normal
  [x: string]: Animal;
}


interface TestNotOkay {
  [x: number]: number; // Numeric index type 'number' is not assignable to string index type 'string'.
  [x: string]: string;
}

interface Test {
  x: number;
  [propName: string]: number | string; // normal
}

interface TestOkay {
  [x: number]: number;
  [x: string]: number | string; // normal
}

 

Posted by pleigh on Sat, 14 May 2022 21:39:56 +0300