[TypeScript notes] basic type, interface, function and generic type

Posted by Komodo on Fri, 04 Mar 2022 18:26:27 +0100

1, Foundation type

  1. Boolean value
    let isDone: boolean = false

  2. number
    All numbers in TypeScript are floating point numbers.
    It supports decimal and hexadecimal literals, as well as binary and octal literals in ES 2015.
    let count: number = 10

  3. character string
    let name: string = 'lyb'

  4. array
    Writing method 1:
    Element type []:
    let list: number[] = [1, 3, 5]

    Method 2:
    Array type < element type >:
    let list: Array<number> = [1, 3, 5]

  5. Tuple
    Tuples allow an array to represent a known number and type of elements, and each element type does not have to be the same.

    let tuple: [string, number];
    tuple = ['hello', 520] // correct
    tuple2 = [520, 'hello'] // error
    

    When accessing an element that is out of bounds, the union type is used instead: (question?)

    x[3] = 'world'; // Why does my editor report an error???
    console.log(x[5].toString()); // Why does my editor report an error???
    
  6. Enum enum
    A set of values can be given friendly names.

    a. By default: Numbering from 0:

    enum Color {
      Red,
      Green,
      Blue
    }
    
    let c: Color = Color.Green; // 1
    

    b. In the case of manually specifying a value:

      enum Color {
        Red = 1,
        Green = 4,
        Blue
      }
    
      let c: Color = Color.Blue; // 5
    

    One convenience provided by enumeration type is that you can get its name from the value of enumeration type:

    enum Color {
      Red = 1,
      Green = 4,
      Blue
    }
    let colorName: string = Color[4]; // Green
    
  7. any value
    Specify a type for variables that are uncertain during the programming phase.

    let list1: any = 4;
    let list2: any = 'lyb';
    let list3: any = [1, 2, 3];
    
    let list4: any[] = [1, true, 'free']
    
  8. Null void
    To some extent, void type is the opposite of any type. Indicates that there is no type. When a function has no return value, its return value type is void.

    const warnUser = (): void => {
      alert('this is my warning message~')
    }
    
    let a: void = undefined
    
  9. null and undefined
    In typescript, null and undefined are defined by their own types, which are null and undefined respectively.

    let u: undefined = undefined;
    let n: null = null;
    

    By default: null and undefined are subtypes of all types. You can assign null and undefined to variables of type number.

  10. Never existed type never
    never types are the return value types of function expressions or arrow function expressions that always throw exceptions or have no return value at all.
    never is a subtype of all types and can be assigned to any type.

    // The function returning never must have an unreachable end point
    function error(message: string): never {
      throw new Error(message);
    }
    
    // The inferred return value type is never
    function fail() {
      return error('something failed');
    }
    
    // The function returning never must have an unreachable end point
    function infiniteLoop(): never {
      while(true) {}
    }
    
  11. Type Asserts
    Type assertions, like type conversions in other languages, have no run-time impact, but only work at the compilation stage

    a. Writing method I

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

    b. Writing method 2

    let svlength2: number = (someValue as string).length;
    console.log(svlength2);
    

    Conclusion: the two writing methods are equivalent. When using JSX in TypeScript, only as syntax assertions are allowed.

2, interface

  1. introduce
    The core principle of TypeScript is to type check the structure of the value.
    It is sometimes called "duck type discrimination" or "structural subtype".
    The function of interfaces is to name these types and define contracts for your code or third-party code.

  2. Preliminary study on interface

    interface LabelledValue {
      label: string;
    }
    
    function printLable(labelledObj: LabelledValue) {
      console.log(labelledObj.label);
    }
    
    let myObj = {
      size: 10,
      label: "Size 10 Ojb"
    }
    
    printLable(myObj);
    

    As long as the incoming object meets the conditions in the above interface, it is allowed! It should be noted that the type checker will not check the order of attributes, as long as the corresponding attributes exist and the types are correct.

  3. Optional properties (?)
    Not all attributes in the interface are required.

    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'});
    console.log(mySquare); // {"color": "black","area": 100}
    

    Add one after the optional attribute name? Symbol

    Benefits of optional attributes:

    • Possible attributes can be predefined
    • You can catch errors when referring to properties that do not exist
  4. Read only attribute (readonly)
    Some object properties can only change their values when they are created. Use readonly to specify a read-only property before the property name.

    interface Point {
      readonly x: number;
      readonly y: number;
    }
    
    let p1: Point = { x: 10, y: 20 };
    p1.x = 5; // error
    
    • TypeScript has readonlyarray < T > type to ensure that the created array cannot be modified:
      let a: number[] = [1, 23, 4]
      let ro: ReadonlyArray<number> = a;
      ro[1] = 12; // error
      ro.push(5); // error
      ro.length =  100; // error
      a = ro; // error
      
    • a=ro, you can see that even if the entire ReadonlyArray is assigned to an ordinary array, it is not allowed, but it can be overridden with type assertion:
      a = ro as number[]

    Note: readonly VS const
    Use const as a variable and readonly as an attribute

  5. Additional attribute checks
    Look at the following code. When calling the createSquare function, if the parameter passed in is color instead of color, an error will be reported.

    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({colour: 'black'}) ; // report errors
    

    Because object literals are treated specially, they go through additional property checks.
    There are three ways to solve this problem:

    • Type Asserts
      let mySquare = createSquare({colour: 'black'} as SquareConfig) ;
    • Index signature
      interface SquareConfig {
        color?: string;
        width?: number;
        [propName: string]: any;
      }
      
    • Assign an object to another variable
      // Note: if the attribute in the object has at least one configuration item in the interface, such as deleting width, an error will be reported
      let squareOptions = {colour: 'black', width: 100};
      let mySquare = createSquare(squareOptions);
      
  6. Function type
    In addition to describing ordinary objects, interfaces can also describe function types.

    // 1. Define function type interface
    interface SearchFn {
      (sourse: string, subString: string): boolean;
    }
    
    // 2. Use
    let mySearch: SearchFn;
    
    mySearch = function(sourse: string, subString: string) {
      let res = sourse.search(subString)
      return res > -1
    }
    
    mySearch = function(src: string, sub: string): boolean {
      let res = src.search(sub);
      return res > -1;
    }
    
    // Type inference
    mySearch = function(src, sub){
      let res = src.search(sub);
      return res > -1;
    }
    
  7. Indexable type (not quite understood)

    • String index
    • Digital index

3, function

Functions in TS can also create named functions and anonymous functions

  1. Function type
    Annotation method of function:

    • Function declaration method:
    function fn(a: number, b: number): number { return a + b }
    
    • Annotation method of function expression:
    // The inferred type writing method is adopted (the type is specified on the left and there is no type on the right)
    let fn: (a: number, b: number) => {} 
        = function(a, b) { return a: 1 }
    
  2. Optional and default parameters
    Add after parameter? Symbol representing optional parameters

    function buildName (firstName: string, lastName?: string) {
      return firstName + " " + lastName;
    }
    
    

    The parameter directly provides the default value =, which represents the default parameter

    function buildName2 (firstName: string, lastName = 'smith') {
      return firstName + " " + lastName;
    }
    
  3. Residual parameters
    If you want to operate multiple parameters at the same time, or you don't know how many parameters will be passed in, you can use arguments to access all the passed in parameters.

    use... Symbol representing the remaining parameters

    function buildName3 (firstName: string, ...restOfName: string[]) {
      return firstName + " " + restOfName.join(" ");
    }
    
  4. Function overloading
    Meaning: the meaning is clearer

    function reverse(x: number): number;
    function reverse(x: string): string;
    function reverse(x: string | number) {
      if(typeof x === 'string') {
        return x.split('').reverse().join('')
      }
    
      if(typeof x === 'number') {
        return Number(x.toString().split('').reverse().join(''))
      }
    }
    

4, generic

  1. introduce
    In software engineering, we not only need to create a consistent API, but also consider reusability.
    Generics can be used to create reusable components that can support multiple types of data.

  2. First knowledge of generics
    Define generics:

    function identity<T>(arg: T): T {
      return arg;
    }
    

    T: Type variable
    In this way, we can know that the parameter type is the same as the return value type

    Use generics:

    • Method 1:
      let output = identity<string>("mystring")
    • Method 2:
      let output = identity("mystring")
  3. Using generic variables

    // Writing method 1:
    function loggingIdentity<T>(arg: T[]): T[] {
      return arg;
    }
    
    // Method 2:
    function loggingIdentity1<T>(arg: Array<T>): Array<T> {
      return arg;
    }
    
  4. generic types

    • Generic functions:
    function identity<T>(arg: T): T {
      return arg;
    }
    
    // Different generic parameter names can be used as long as they correspond in quantity and form
    let myIdentity: <U>(arg: U): U => U = identity;
    
    
    • Use object literals with call signatures to define generic functions:
    function identity<T>(arg: T): T {
      return arg;
    }
    
    let myIdentity: {<U>(arg: U): U} = identity;
    
    • Introducing generic interfaces:
    interface GenericIdentityFn {
      <T>(arg: T): T;
    }
    
    function identity<T>(arg: T): T {
      return arg;
    }
    
    let myIdentity: GenericIdentityFn = identity;
    let myIdentity2: {<U>(arg: U): U} = identity;
    
    • Final generic notation:
    interface GenericIdentityFn<T> {
      (arg: T): T;
    }
    
    function identity<T>(arg: T): T {
      return arg;
    }
    
    let myIdentity: GenericIdentityFn<number> = identity;
    
  5. Generic constraints (extensions)
    If there is no type constraint, the parameter arg of the loggingIdentity function cannot use the attribute length it does not have

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

Topics: Javascript TypeScript