typescript 零散的

typescript in vue

props type

<script>
import { defineComponent } from 'vue';
import type {PropType} from 'vue';

type Resturant = {
  id:string
  people:Array<string>
  total:number
  anyThing:any  
}

export default defineComponent({
    props:{
      resturant:{
        type: Object as PropType<Resturant>,
        required: true
      }
    }
})

</script>

advanced ttypescript

TIP

tsc ts.ts && node ts.js

可选链

//advanced typescript fundamental
type SerialicationOptions = {
    formatting?:{
      indent?:number;
    };
  };
  
  function serializeJSON(value:any,options?: SerialicationOptions){
    const indent = options?.formatting?.indent??2;
    return JSON.stringify(value,null,indent)
  }
  
  const user = {
    name:"ajn404 n-gray-moon",
    bilibili:'狗粮长'
  }
  
  const json = serializeJSON(user,{
    formatting:{
      indent:0
    }
  });

  console.log(json);
编译后
function serializeJSON(value, options) {
    var _a, _b;
    var indent = (_b = (_a = options === null || options === void 0 ? void 0 : options.formatting) === null || _a === void 0 ? void 0 : _a.indent) !== null && _b !== void 0 ? _b : 2;
    return JSON.stringify(value, null, indent);
}
var user = {
    name: "ajn404 n-gray-moon",
    bilibili: '狗粮长'
};
var json = serializeJSON(user, {
    formatting: {
        indent: 0
    }
});
console.log(json);

断言和谓词

File not found
编译后
function assertIsNumber(value, name) {
    if (typeof value !== "number") {
        throw Error("Expect \"".concat(name, "\" to be a number"));
    }
}
function range(from, to) {
    assertIsNumber(to, 'to');
    assertIsNumber(from, 'from');
    var values = [];
    for (var i = from; i < to; i++) {
        values.push(i);
    }
    return values;
}
console.log(range("A", "F"));

NonNullable

function assertIsNonNullish<T>(
    value:T,
    message:string
):asserts value is NonNullable<T>{
    if(value===null||value===undefined){
        throw Error(message);
    }
}

const root = document.getElementById('app');
assertIsNonNullish(root,"找不到#app的dom元素");

root.addEventListener("click",e=>{
    console.log(e);
})
编译后
function assertIsNonNullish(value, message) {
    if (value === null || value === undefined) {
        throw Error(message);
    }
}
var root = document.getElementById('app');
assertIsNonNullish(root, "找不到#app的dom元素");
root.addEventListener("click", function (e) {
    console.log(e);
});

private

class Counter {
    private _value = 0;
    increment(){
        this._value+=1;
    }

    get count(){
        return this._value
    }
}

const couter = new Counter();
couter.increment();
couter.increment();
couter.increment();

console.log(couter.count);

编译后

tsc ts04.ts报错

ts04.ts:7:9 - error TS1056: Accessors are only available when targeting ECMAScript 5 and higher.

7     get count(){
          ~~~~~

Found 1 error in ts04.ts:7

使用tsc ts04 -t es5

实现private使用了weakMap

编译后
var Counter = /** @class */ (function () {
    function Counter() {
        this._value = 0;
    }
    Counter.prototype.increment = function () {
        this._value += 1;
    };
    Object.defineProperty(Counter.prototype, "count", {
        get: function () {
            return this._value;
        },
        enumerable: false,
        configurable: true
    });
    return Counter;
}());
var couter = new Counter();
couter.increment();
couter.increment();
couter.increment();
console.log(couter.count);

closure闭包

function createCounter(){
    let value= 0 ;
    return {
        increment(){
            value++;
        },
        get coute(){
            return value
        }
    }
}

const couters = createCounter();

couters.increment();
couters.increment();
couters.increment();
couters.increment();

console.log(couters.coute);
编译后
function createCounter() {
    var value = 0;
    return {
        increment: function () {
            value++;
        },
        get coute() {
            return value;
        }
    };
}
var couters = createCounter();
couters.increment();
couters.increment();
couters.increment();
couters.increment();
console.log(couters.coute);
//4

readonly array type

function intersperse<T>(array:readonly T[],separator : T):T[]{
    const newArray:T[] = [];
    for(const element of array){
        if(newArray.length!==0){
            newArray.push(separator);
        }
        newArray.push(element);
    }

    return newArray
}

const values:ReadonlyArray<string> = ["A","B","C","D"];
const valueWithSeparator = intersperse(values,"X");
console.log(values);
console.log(valueWithSeparator);
编译后
function intersperse(array, separator) {
    var newArray = [];
    for (var _i = 0, array_1 = array; _i < array_1.length; _i++) {
        var element = array_1[_i];
        if (newArray.length !== 0) {
            newArray.push(separator);
        }
        newArray.push(element);
    }
    return newArray;
}
var values = ["A", "B", "C", "D"];
var valueWithSeparator = intersperse(values, "X");
console.log(values);
console.log(valueWithSeparator);

readonly tuple type

function swap<T,U>(tuple:readonly [T,U]):[U,T]{
    const [first,second] = tuple;
    return [second,first];
}

const keyValuePair: readonly[number,string] = [1,"one"];
const valueKeyPair = swap(keyValuePair);
console.log(keyValuePair);
console.log(valueKeyPair);
编译后
function swap(tuple) {
    var first = tuple[0], second = tuple[1];
    return [second, first];
}
var keyValuePair = [1, "one"];
var valueKeyPair = swap(keyValuePair);
console.log(keyValuePair);
console.log(valueKeyPair);

as const

const ORIGIN ={
    x:1,
    y:1
} as const;
ORIGIN.x =10;//无法分配到"x",因为它是只读属性

上述运行时不会报错,但下面这种会

const freezeOrigin = Object.freeze({
    x:1,
    y:1
}as const)
freezeOrigin.x = 1;//无法分配到"x",因为它是只读属性

as const用于数组

const ORIGIN ={
    x:1,
    y:1
} as const;
ORIGIN.x =10;//无法分配到"x",因为它是只读属性

use const asserts in enum-style obj

const HTTPRequestMethod = {
    GET:'GET',
    POST:'POST'
}as const;
type ValueOf<T> = T[keyof T];
type HTTPRequestMethodType = ValueOf<typeof HTTPRequestMethod>;
async function fetchJSON(
    url:string,
    method: HTTPRequestMethodType,
){
    const response = await fetch(url,{method});
    return response.json();
}

fetchJSON("http://",HTTPRequestMethod.GET).then(res=>{});
编译后
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __generator = (this && this.__generator) || function (thisArg, body) {
    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
    return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
    function verb(n) { return function (v) { return step([n, v]); }; }
    function step(op) {
        if (f) throw new TypeError("Generator is already executing.");
        while (_) try {
            if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
            if (y = 0, t) op = [op[0] & 2, t.value];
            switch (op[0]) {
                case 0: case 1: t = op; break;
                case 4: _.label++; return { value: op[1], done: false };
                case 5: _.label++; y = op[1]; op = [0]; continue;
                case 7: op = _.ops.pop(); _.trys.pop(); continue;
                default:
                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
                    if (t[2]) _.ops.pop();
                    _.trys.pop(); continue;
            }
            op = body.call(thisArg, _);
        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
    }
};
var HTTPRequestMethod = {
    GET: 'GET',
    POST: 'POST'
};
function fetchJSON(url, method) {
    return __awaiter(this, void 0, void 0, function () {
        var response;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0: return [4 /*yield*/, fetch(url, { method: method })];
                case 1:
                    response = _a.sent();
                    return [2 /*return*/, response.json()];
            }
        });
    });
}
fetchJSON("http://", HTTPRequestMethod.GET).then(function (res) { });

所谓NonNullable

type NonNullable<T> = T & {};

type NonNullable<T> = T extends null | undefined ? never:T;
type A = NonNullable<string>;
type B = NonNullable<null>;

应用

type EmailRecipient = string | string[] | null | undefined;
type NonNullableEmailRecipient = NonNullable<EmailRecipient>;
//等同于
//type NonNullableEmailRecipient = string | string[]

所谓ReturnType

type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;

name type parameters

type ReturnType<TFunctions extends (...args:any)=> any> = TFunctions extends (...args:any)  => infer TReturnType?TReturnType :any;

template in ts

比如css类型

type Dimention = 'block'|'inline';
type Direction = 'left' | 'right' | 'top' | 'bottom';
type MarginProperty = `margin-${Dimention}-${Direction}`
//type MarginProperty = "margin-block" | "margin-inline"

type MarginUnit = 'px'|'vw'|'%' |'vh';
type MarginValue = `${number}${MarginUnit}`
type MarginPropertyDeclaration = [MarginProperty,MarginValue];

// const margin :MarginPropertyDeclaration = ['margin-block-left','12'];
//不能将类型“["margin-block", "12"]”分配给类型“MarginPropertyDeclaration”

const margin :MarginPropertyDeclaration = ['margin-block-left','12px'];

相对复杂的案例

//“相对复杂“

// type Record<K extends keyof any, T> = {
//     [P in K]: T;
// };


type PropGetters <TObj extends Record<string,any>> = {
    [Tkey in string & keyof TObj as `get${Capitalize<Tkey>}`]:()=>TObj[Tkey];
}

function createGetterObject <TObj extends Record<string,any>>(obj:TObj):PropGetters<TObj>{
    const newObj:any = {};
    for(const key of Object.keys(obj)){
        const capitalizedKey = key[0].toUpperCase()+key.substr(1);
        const getterKey = `get${capitalizedKey}`;
        newObj[getterKey] = ()=> obj[key];
    }
    return newObj
}

const user = createGetterObject({
    id:123,
    name:'王德发',
    phone:12510102031
})

console.log(user.getId);
开始ts系统性学习