Typescript03: full solution of function

Annotation of function

The dimension of a function contains

  • parameter
  • Return value
function fn(a: string): string {};
let fn: (a: string) => string = function(a) {};

type callback = (a: string): string;
interface ICallBack {
	(a: string): string;
}
let fn: callback = function(a) {};
let fn: ICallBack = function(a) {};

parameter

Optional parameters

let div = document.querySelector('div');
function css(el: HTMLElement, attr: string, val?: any) {
}
// set up
div && css( div, 'width', '100px' );
// obtain
div && css( div, 'width' );

Default parameters

We can also set default values for parameters

  • Parameters with default values are also optional
  • Parameters with default values can automatically derive types based on values
function sort(items: Array<number>, order = 'desc') {}
sort([1,2,3]);
// You can also limit values by combining types
function sort(items: Array<number>, order:'desc'|'asc' = 'desc') {}
// ok
sort([1,2,3]);
// ok
sort([1,2,3], 'asc');
// error
sort([1,2,3], 'abc');

Remaining parameters

The remaining parameter is an array, so you must pay attention to it when labeling

interface IObj {
    [key: string]: any;
}
function merge(target: IObj, ...others: Array<IObj>) {
    return others.reduce((prev, current) => {
        prev = Object.assign(prev, current);
        return prev;
    }, target);
}
let newObj = merge({ x: 1 }, { y: 2 }, { z: 3 });

this in function

Ordinary function

For ordinary functions, this will change as the calling environment changes
So by default, this in a normal function is labeled any
But we can explicitly label the type of this on the first parameter bit of the function (it does not occupy the actual parameter position)

interface T {
    a: number;
    fn: (x: number) => void;
}
let obj1: T = {
    a: 1,
    fn(x: number) {
        //any type
        console.log(this);
    }
}
let obj2: T = {
    a: 1,
    fn(this: T, x: number) {
        //The first parameter bit indicates the type of this, which has no effect on the actual parameter
        console.log(this);
    }
}
obj1.fn(1);
obj2.fn(1);


Assertions can be resolved, but they are too complex

Arrow function

this of arrow function can't be labeled like ordinary function
Its this dimension type depends on its scope this dimension type

interface T {
    a: number;
    fn: (x: number) => void;
}
let obj2: T = {
    a: 2,
    fn(this: T) {
        return () => {
            // T
            console.log(this);
        }
    }
}

function overloading

Sometimes, the same function will receive different types of parameters and return different types of return values
We can use function overloading to implement

For example, you want parameters to form corresponding relationships

function showOrHide(ele: HTMLElement, attr: string, value: 'block' | 'none' | number) {
    //
}
let div = document.querySelector('div');
if (div) {
    showOrHide(div, 'display', 'none');
    showOrHide(div, 'opacity', 1);
    // Error, no error is reported, but it will actually make an error. Although different types of parameters can be received at the same time through joint type processing, there is a combination mode between multiple parameters. What we need is a corresponding relationship
    showOrHide(div, 'display', 1);
}

function overloading

Define multiple rules:

  1. What parameters should be set when passing in display
  2. What parameters should be set when passing in opacity
function showOrHide(ele: HTMLElement, attr: 'display', value: 'block' | 'none');
function showOrHide(ele: HTMLElement, attr: 'opacity', value: number);

function showOrHide(ele: HTMLElement, attr: string, value: any) {
    ele.style[attr] = value;
}
let div = document.querySelector('div');
if (div) {
    showOrHide(div, 'display', 'none');
    showOrHide(div, 'opacity', 1);
    // Different parameter correspondence can be set through function overloading
    showOrHide(div, 'display', 1);
}

Overloaded function types only need to define structures, no entities, similar interfaces, and batch settings
Realize the following requirements:

  1. If two parameters are passed in, the second parameter must be an object
  2. If three parameters are passed in, the second parameter must be a string
interface PlainObject {
    [key: string]: string | number;
}

function css(ele: HTMLElement, attr: PlainObject);  // 
function css(ele: HTMLElement, attr: string, value: string | number);
function css(ele: HTMLElement, attr: any, value?: any) {
    if (typeof attr === 'string' && value) {
        ele.style[attr] = value;
    }
    if (typeof attr === 'object') {
        for (let key in attr) {
            ele.style[attr] = attr[key];
        }
    }
}
let div = document.querySelector('div');
if (div) {
    css(div, 'width', '100px');
    css(div, {
        width: '100px'
    });
    // error
    css(div, 'width');
}

Posted on Sat, 06 Jun 2020 02:47:39 -0700 by danville