<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          寫了3個(gè)月TypeScript,我學(xué)到了什么?

          共 20502字,需瀏覽 42分鐘

           ·

          2021-05-26 00:56

          之前閱讀vue源碼的時(shí)候發(fā)現(xiàn)有TypeScript,一臉懵逼,因此需要入個(gè)門。

          最近在新環(huán)境的日常工作中也需要用到TypeScript,學(xué)習(xí)過程中遇到一些疑惑,做了記錄。

          個(gè)人覺得還是比較適合TypeScript入門的同學(xué)閱讀的,因?yàn)槲矣龅降倪@些疑惑,可能你也會(huì)遇到。

          ?ts類型中的?,<>意思是什么??什么是duck typing??constructor之前的變量定義是什么??declare是什么??ts中unknown, void, null和undefined,never區(qū)別是什么??ts中的泛型約束是什么??數(shù)組類型的兩種定義方式?ts中的類型斷言?泛型函數(shù)與泛型接口?如何理解as const??declare global是什么意思??如何在TypeScript環(huán)境增加一個(gè)全局變量??interface可以繼承嗎??typescript中的&是什么意思??interface與type的區(qū)別是什么??enum作為一種類型是什么意思??項(xiàng)目中xxx.d.ts的declare module '*.scss'是什么意思?declare module還可以做什么??typescript如何約束Promise的類型??typescript中的keyof如何使用??typescript中的typeof如何使用??typescript中的non-null operator是什么?

          ts類型中的?意思是什么?

          // https://github.com/vuejs/vue/blob/dev/src/core/observer/watcher.js
          before: ?Function;
          options?: ?Object,

          這是ts的interface中的一個(gè)概念。ts的interface就是"duck typing"或者"structural subtyping",類型檢查主要關(guān)注the shape that values have。因此我們先來熟悉一下interface,再引出?的解釋。

          TypeScript普通方式定義函數(shù):

          function print(obj: {label: string}) {
          console.log(obj.label);
          }
          let foo = {size: 10, label: "這是foo, 10斤"};
          print(foo);

          TypeScript interface方式定義函數(shù):

          interface labelInterface {
          label: string;
          }
          function print(obj: labelInterface) {
          console.log(obj.label);
          }
          let foo = {size: 10, label: "這是foo, 10斤"};
          print(foo);

          進(jìn)入正題,TypeScript中的是什么意思?Optional Properties。

          Optional Properties

          ?并不是interface中的所有屬性都是required的,一些存在特定條件下,一些根本不存在。?Optional Properties適用于"option bags"的設(shè)計(jì)模式,這種設(shè)計(jì)模式意思是:我們傳遞一個(gè)對(duì)象到函數(shù),這個(gè)函數(shù)只有幾個(gè)屬性,沒有其他更多的屬性。?Optional Property的好處在于,清晰的看清楚有哪些屬性,防止傳入不屬于該interface的屬性。

          interface SquareConfig {
          color?: string;
          width?: number;
          }
          function createSquare(config: SquareConfig): {color: string; area: number} {
          let newSquare = {color: "white", area: 100};
          if (config.clor) {
          // Error: Property 'clor' does not exist on type 'SquareConfig'
          newSquare.color = config.color;
          }
          if (config.width) {
          newSquare.area = config.width * config.width;
          }
          return newSquare;
          }
          let mySquare = createSquare({color: "black"});

          Interfaces with optional properties are written similar to other interfaces, with each optional property denoted by a ? at the end of the property name in the declaration.


          什么是?和Optional Properties呢?interface的某些非required屬性名的末尾,添加?這是一個(gè)optional property,其實(shí)就是字面意思,條件屬性。

          Optional Property只是屬性名,也就是options?: ?Object,中options后的問號(hào),拿屬性值類型前的問號(hào)是什么意思,也就是?Object,是什么意思?此處的問號(hào)代表屬性值類型是否可以是null類型,但是只有strictNullChecks為on時(shí),值類型才能為null。

            /**
          * @type {?number}
          * strictNullChecks: true -- number | null
          * strictNullChecks: off -- number
          * */
          var nullable;

          我們的例子中,options?:?Object的意思是options的值類型可以是Object,null(僅在strictNullChecks為true時(shí)允許)。

          ts類型中的<>什么意思?

          deps: Array<Dep>a
          newDeps: Array<Dep>

          ts中的數(shù)組類型與java中的定義類似:

          let list: number[] = [1, 2, 3];
          let list: Array<number> = [1, 2, 3];

          什么是duck typing?

          duck test。如果"走路像鴨子,叫聲像鴨子,那么這就是鴨子"。在computer programming,用于'判斷對(duì)象是否可以按照預(yù)期的目的使用'。通常的typing中,適用性取決于對(duì)象的type。duck typing不一樣,對(duì)象的適用性取決于指定method或property的存在與否,而不是取決于對(duì)象自身的類型。

          前端工程師基本都是duck typing,因?yàn)镴avaScript沒有type。 --這話是我說的

          Python3 example

          class Duck:
          def fly(self):
          print("Duck flying")

          class Airplane:
          def fly(self):
          print("Airplane flying")

          class Whale:
          def swim(self):
          print("Whale swimming")

          def lift_off(entity):
          entity.fly()

          duck = Duck()
          airplane = Airplane()
          whale = Whale()

          lift_off(duck) # prints `Duck flying`
          lift_off(airplane) # prints `Airplane flying`
          lift_off(whale) # Throws the error `'Whale' object has no attribute 'fly'`

          Javascript example

          class Duck {
          fly() {
          console.log("Duck flying")
          }
          }
          class Airplane {
          fly() {
          console.log("Airplane flying")
          }
          }
          class Whale {
          swim() {
          console.log("Whale swimming")
          }
          }

          function liftOff(entity) {
          entity.fly()
          }

          const duck = new Duck();
          const airplane = new Airplane();
          const whale = new Whale();

          liftOff(duck); // Duck flying
          liftOff(airplane); // Airplane flying
          liftOff(whale); // Uncaught TypeError: entity.fly is not a function

          constructor之前的變量定義是什么?

          例如vnode的定義:

          export default class VNode {
          tag: string | void;
          data: VNodeData | void;
          children: ?Array<VNode>;
          text: string | void;
          elm: Node | void;
          ns: string | void;
          context: Component | void; // rendered in this component's scope
          key: string | number | void;
          componentOptions: VNodeComponentOptions | void;
          componentInstance: Component | void; // component instance
          parent: VNode | void; // component placeholder node

          // strictly internal
          raw: boolean; // contains raw HTML? (server only)
          isStatic: boolean; // hoisted static node
          isRootInsert: boolean; // necessary for enter transition check
          isComment: boolean; // empty comment placeholder?
          isCloned: boolean; // is a cloned node?
          isOnce: boolean; // is a v-once node?
          asyncFactory: Function | void; // async component factory function
          asyncMeta: Object | void;
          isAsyncPlaceholder: boolean;
          ssrContext: Object | void;
          fnContext: Component | void; // real context vm for functional nodes
          fnOptions: ?ComponentOptions; // for SSR caching
          fnScopeId: ?string; // functional scope id support

          constructor ()
          ...
          }

          http://www.typescriptlang.org/docs/handbook/classes.html typeScript中的class要比es6的多一項(xiàng):property。這和java或者c#中的一致。

          property
          constructor
          method

          實(shí)際上es6提供了一種私有變量,僅僅能在class內(nèi)部訪問。

          class Rectangle {
          #height = 0;
          #width;
          constructor(height, width) {
          this.#height = height;
          this.#width = width;
          }
          }

          冒號(hào)后面的:VNode什么意思?

          export function cloneVNode (vnode: VNode): VNode {
          ...
          }

          TypeScript中的函數(shù)返回值類型。

          declare是什么?

          聲明這是一個(gè)definition。

          ?

          declare是ts中用于寫定義文件的關(guān)鍵字。

          ?

          declare可以定義全局變量,全局函數(shù),全局命名空間,class等等。

          ?

          declare可以按照下面這樣去使用:

          declare var foo:number;
          declare function greet(greeting: string): void;
          declare namespace myLib {
          function makeGreeting(s: string): string;
          let numberOfGreeting: number;
          }
          declare function getWidget(n: number): Widget;
          declare function getWidget(s: string): Widget[];
          declare class Greeter {
          constructor(greeting: string);

          greeting: string;
          showGreeting(): void;
          }




          ts中any,unknown, void, null和undefined,never區(qū)別是什么?

          null,undefined就是js中的意思。

          any: 任意類型,謹(jǐn)慎使用,避免使typescript變成anyscript unknown: 與any類似,但是比any更加安全 void: 通常用于返回值的函數(shù) never:never occur 從來不會(huì)發(fā)生的類型,例如永遠(yuǎn)不會(huì)有結(jié)果的,拋出異常或者死循環(huán)。

          ts中的泛型約束是什么?

          基于string(boolean, Function)類型

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

          loggingIdentity("hello"); // 5
          loggingIdentity(2); // Argument of type 'number' is not assignable to parameter of type 'string'.

          基于自定義的interface

          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;
          }

          loggingIdentity(3); // Error, number doesn't have a .length property
          loggingIdentity({length: 10, value: 3}); // 10

          ts2.8發(fā)布說明

          // https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html
          type TypeName<T> = T extends string
          ? "string"
          : T extends number
          ? "number"
          : T extends boolean
          ? "boolean"
          : T extends undefined
          ? "undefined"
          : T extends Function
          ? "function"
          : "object";

          type T0 = TypeName<string>; // "string"
          type T1 = TypeName<"a">; // "string"
          type T2 = TypeName<true>; // "boolean"
          type T3 = TypeName<() => void>; // "function"
          type T4 = TypeName<string[]>; // "object"

          同時(shí)支持type和interface兩種類型的泛型約束

          interface reduxModel<T> {
          reducers: T extends string ? {[x in T]: () => void}: T,
          }

          type TType = "foo" | "bar" | 'baz'
          interface TInterface {
          "foo": () => void,
          "bar": () => void,
          'baz': () => void
          }

          const ireducers = {
          "foo": () => void
          }

          const model : reduxModel<TType> = {
          reducers: ireducers
          // 正常運(yùn)行
          }

          const model : reduxModel<TInterface> = {
          reducers: ireducers
          // Type '{ foo: () => undefined; }' is missing the following properties from type 'TInterface': "bar", 'baz'
          }

          數(shù)組類型的兩種定義方式

          Array<類型>

          Array后面加一個(gè)<>,<>內(nèi)聲明元素類型。

          type Foo= Array<string>;
          interface Bar {
          baz: Array<{
          name: string,
          age: number,
          }>
          }

          類型[]

          元素類型后面加一個(gè)[]。

          type Foo = string[]
          interface Bar {
          baz : {
          name: string,
          age: number,
          }[]
          }

          ts中的類型斷言

          TypeScript允許我們覆蓋推斷和分析出的視圖類型為我們想要的任意方式,這種機(jī)制叫做類型斷言(Type Assertion),類型斷言會(huì)告訴編譯器你比它更加知道具體是哪種類型,編譯器不用再二次推斷了。類型斷言往往是發(fā)生在編譯器編譯期間,用于提示編譯器如何分析我們的代碼。

          ?語法?遷移js代碼?類型斷言的問題?指定event類型?慎用as any和as unknown?type與類型斷言

          語法

          interface Foo {
          name: string,
          }
          type Any = any;

          let a:Foo = {} as Foo;
          let a:Foo = {} as Any;

          any是任意類型的子類型,所以任意類型都可以被as any,還是建議謹(jǐn)慎使用,避免變?yōu)閍nyscript。

          遷移js代碼

          var foo = {};
          foo.bar = 123; // Error: property 'bar' does not exist on `{}`
          foo.bas = 'hello'; // Error: property 'bas' does not exist on `{}`
          interface Foo {
          bar: number;
          bas: string;
          }
          var foo = {} as Foo;
          foo.bar = 123;
          foo.bas = 'hello'; // 注釋掉這一行也不會(huì)報(bào)錯(cuò)

          類型斷言的問題

          foo.bas = 'hello'; // 注釋掉這一行也不會(huì)報(bào)錯(cuò) 如果是下面的方式就會(huì)報(bào)錯(cuò)了,會(huì)提示缺少bas的定義

          interface Foo {
          bar: number;
          bas: string;
          }
          var foo : Foo= {
          bar: 123
          };

          所以說,類型斷言是不夠嚴(yán)謹(jǐn)?shù)模ㄗh使用var foo : Foo這種方式。

          指定event類型

          function handler (event: Event) {
          let mouseEvent = event as MouseEvent;
          }
          function handler(event: Event) {
          let element = event as HTMLElement; // HTMLElement不是一個(gè)完全的event子類型,因此不能充分重疊,需要加一個(gè)unknown或者any
          }

          二次斷言編譯提示取消:

          function handler(event: Event) {
          let element = event as unknown as HTMLElement; // Okay!
          }

          慎用as any和as unknown

          通常情況是類型斷言S和T的話,S為T的子類型,或者T為S的子類型,這種是相對(duì)安全的。假如是用as any或者as unknown,是非常不安全的。慎用!慎用!

          // 謹(jǐn)慎使用
          as any
          as known

          type與類型斷言

          type keys = 'foo' | 'bar' | 'baz'obj[key as keys]是什么意思?與variable:type類似,這是另外一種類型約束。

          如果不明白的花,看完下面這個(gè)demo就明白了。

          type keys = 'foo' | 'bar' | 'baz'
          const obj = {
          foo: 'a',
          bar: 'b',
          baz: 'c'
          }
          const test = (key:any) => {
          return obj[key] ; // 提示錯(cuò)誤 type 'any' can't be used to index type '{ foo: string; bar: string; baz: string; }'.
          }

          如何解決這個(gè)報(bào)錯(cuò)呢?第一種方式:類型約束

          const test = (key:keys) => {
          return obj[key] ;
          }

          第二種方式:類型斷言(這種方式常用于第三方庫的callback,返回值類型沒有約束的情況)

          const test = (key:any) => {
          return obj[key as keys] ;
          }

          需要注意:obj[key as keys]中keys的類型可以少于obj的類型,反過來obj的屬性不能少于keys的類型。

          泛型函數(shù)與泛型接口

          泛型函數(shù)

          想想一個(gè)場景,我們希望函數(shù)的輸入與輸出類型一致。你可能會(huì)這樣做,但這并不能保障輸入與輸出類型一致。

          function log(value: any):any {
          return value;
          }

          通過泛型函數(shù)可以精準(zhǔn)實(shí)現(xiàn):函數(shù)名后加一個(gè)<T>這里的T可以理解為泛型的名字。指定輸入類型為T,返回值為T。

          function log<T>(value: T):T {
          return value;
          }

          這是一個(gè)泛型函數(shù)實(shí)例,如何定義一種泛型函數(shù)類型呢?

          type Log = <T>(value: T) => T

          使用泛型函數(shù)類型約束函數(shù):

          let log : Log = function <T>(value: T):T {
          return value;
          }

          泛型接口

          接口所有屬性靈活,輸入輸出一致即可。

          interface Log {
          <T>(value: T): T
          }
          let myLog: Log = log
          myLog("s")// "s"
          myLog(1)// 1

          接口所有屬性必須為同一類型。

          interface Log<T> {
          (value: T): T
          }
          let myLog: Log<string> = log
          myLog("s")// "s"
          myLog(1)// Error

          ts中的<>

          在ts中,遇到<>的話,尖括號(hào)中間大多情況下都是類型。

          ?Array<string>?<string>[]?function <T>(value: T): T { ... }?type MyType = <T>(value : T) => T?interface MyInterface<T> { (value: T): T }

          如何理解as const?

          ?為了解決let賦值問題的,將一個(gè)mutable的變量改為readonly。?避免將類型推斷為聯(lián)合類型。

          為了解決let賦值問題的,將一個(gè)mutable的變量改為readonly。

          let x = "hello";
          x = "world"; // 報(bào)錯(cuò)

          第一種方式 const

          const x = "hello"

          第二種方式 "hello"類型

          let x: "hello" = "hello";
          x = "world"; //

          第三種方式 discriminated unions

          type Shape =
          | { kind: "circle", radius: number }
          | { kind: "square", sideLength: number }
          function getShapes(): readonly Shape[] {
          // to avoid widening in the first place.
          let result: readonly Shape[] = [
          { kind: "circle", radius: 100, },
          { kind: "square", sideLength: 50, },
          ];
          return result;
          }

          第四種方式 as const

          .tsx類型文件

          // Type '10'
          let x = 10 as const;

          // Type 'readonly [10, 20]'
          let y = [10, 20] as const;

          // Type '{ readonly text: "hello" }'
          let z = { text: "hello" } as const;

          非.tsx類型文件

          // Type '10'
          let x = <const>10;

          // Type 'readonly [10, 20]'
          let y = <const>[10, 20];

          // Type '{ readonly text: "hello" }'
          let z = <const>{ text: "hello" };

          優(yōu)化discriminated unions

          function getShapes() {
          let result = [
          { kind: "circle", radius: 100, },
          { kind: "square", sideLength: 50, },
          ] as const;

          return result;
          }

          for (const shape of getShapes()) {
          // Narrows perfectly!
          if (shape.kind === "circle") {
          console.log("Circle radius", shape.radius);
          }
          else {
          console.log("Square side length", shape.sideLength);
          }
          }

          避免將類型推斷為聯(lián)合類型。

          避免將類型推斷為 (boolean | typeof load)[],而是推斷為[boolean, typeof load]。

          export function useLoading() {
          const [isLoading, setState] = React.useState(false);
          const load = (aPromise: Promise<any>) => {
          setState(true);
          return aPromise.finally(() => setState(false));
          };
          return [isLoading, load] as const; // infers [boolean, typeof load] instead of (boolean | typeof load)[]
          }

          declare global是什么意思?

          是為了在全局命名空間做聲明,比如為對(duì)象增加一個(gè)未定義的屬性。

          為Window增加csrf的定義

          declare global {
          interface Window {
          csrf: string;
          }
          }

          為String增加fancyFormat的定義

          declare global {
          /*~ Here, declare things that go in the global namespace, or augment
          *~ existing declarations in the global namespace
          */
          interface String {
          fancyFormat(opts: StringFormatOptions): string;
          }
          }

          注意global作用域只能用于導(dǎo)出模塊或者外部的模塊聲明

          Augmentations for the global scope can only be directly nested in external modules or ambient module declarations.

          如何在TypeScript環(huán)境增加一個(gè)全局變量?

          比如我們想要實(shí)現(xiàn)下面的效果,但是會(huì)報(bào)錯(cuò)Property '__INITIAL_DATA__' does not exist

          <script>
          window.__INITIAL_DATA__ = {
          "userID": "536891193569405430"
          };
          </script>
          const initialData = window.__INITIAL_DATA__; // 報(bào)錯(cuò)

          使用類型斷言

          const initialData = (window as any).__INITIAL_DATA__;
          type InitialData = {
          userID: string;
          };

          const initialData = (window as any).__INITIAL_DATA__ as InitialData;
          const userID = initialData.userID; // Type string

          聲明全局變量

          declare var __INITIAL_DATA__: InitialData;
          const initialData = __INITIAL_DATA__;
          const initialData = window.__INITIAL_DATA__;

          在es模塊中,有import,export的,需要這樣做:

          export function someExportedFunction() {
          // ...
          }

          declare global {
          var __INITIAL_DATA__: InitialData;
          }
          const initialData = window.__INITIAL_DATA__;

          如果在很多文件都用到的話,可以用一個(gè)globals.d.ts文件。

          利用interface合并

          interface Window {
          __INITIAL_DATA__: InitialData;
          }
          const initialData = window.__INITIAL_DATA__;

          在js模塊中需要像下面這樣:

          export function someExportedFunction() {
          // ...
          }

          declare global {
          interface Window {
          __INITIAL_DATA__: InitialData;
          }
          }

          const initialData = window.__INITIAL_DATA__;

          interface可以繼承嗎?

          可以的。

          interface Base {
          foo: string;
          }

          interface Props extends Base {
          bar: string
          baz?: string
          }

          const test = (props: Props) => {
          console.log(props);
          }

          test({ foo: 'hello' }) // Property 'bar' is missing in type '{ foo: string; }' but required in type 'Props'
          test({ foo: 'hello', bar: 'world' })

          當(dāng)Props繼承了Base之后,實(shí)際上它最終變成了下面這樣:

          interface Props extends Base {
          foo: string;
          bar: string
          baz?: string
          }

          Props可以覆蓋Base嗎?可以,但是只能是required覆蓋optional,optional不能覆蓋required。

          // ?
          interface Base {
          foo?: string;
          }

          interface Props extends Base {
          foo: string;
          bar: string
          baz?: string
          }
          // ?
          interface Base {
          foo: string;
          }

          interface Props extends Base {
          foo?: string;
          bar: string
          baz?: string
          }

          typescript中的&是什么意思?

          在react的dts文件中有這樣一個(gè)定義。

          type PropsWithChildren<P> = P & { children?: ReactNode };

          typescript中的&指的是交叉類型。

          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);
          };

          知道&是ts中的交叉類型以后,我們就明白PropsWithChildren的意思了,而且也明白為什么react的函數(shù)式組件會(huì)比普通函數(shù)組件多了children屬性。

          它的意思是PropsWithChildren類型是P和對(duì)象{children?: ReactNode}的交叉類型,也就是通過&連接兩個(gè)對(duì)象之后,最終生成的對(duì)象是擁有children這個(gè)可選屬性的。

          interface與type的區(qū)別是什么?

          An interface can be named in an extends or implements clause, but a type alias for an object type literal cannot. An interface can have multiple merged declarations, but a type alias for an object type literal cannot.

          1.interface可以繼承(比如用extends),type不可以2.interface可以實(shí)現(xiàn)有多個(gè)合并聲明,type不可以

          enum作為一種類型是什么意思?

          在閱讀pixi.js的源碼中,發(fā)現(xiàn)有將enum作為了一種類型。

          enum也可以作為一種類型去約束。

          // pixi/constants
          export enum BLEND_MODES {
          NORMAL = 0,
          ADD = 1,
          MULTIPLY = 2,
          SCREEN = 3,
          OVERLAY = 4,
          }

          export enum ANOTHER_ENUM {
          FOO = 5,
          BAR = 6
          }

          import { BLEND_MODES } from '@pixi/constants';

          export class Sprite extends Container
          {
          public blendMode: BLEND_MODES;
          constructor(){
          this.blendMode = BLEND_MODES.NORMAL; // 最佳
          // this.blendMode = 0 這樣是可以的,次之
          // this.blendMode = ANOTHER_ENUM.FOO 這樣ts會(huì)報(bào)錯(cuò)
          }
          }

          項(xiàng)目中xxx.d.ts的declare module '*.scss'是什么意思?declare module還可以做什么?

          項(xiàng)目中xxx.d.ts的declare module '*.scss'是什么意思?

          // externals.d.ts
          declare module '*.scss'

          默認(rèn)情況下import style from 'style.scss'在ts的ide校驗(yàn)器里會(huì)報(bào)錯(cuò),那就用d.ts假定定義所有scss結(jié)尾的文件是module。--社長

          假設(shè)將declare module '*.scss'注釋掉,ide會(huì)報(bào)錯(cuò),但是可以通過lint。

          declare module還可以做什么?

          當(dāng)我們引入了一個(gè)微軟官方@types/*中不存在的自定義包時(shí),ide會(huì)報(bào)錯(cuò)。

          例如下面這樣:

          如何解決這個(gè)報(bào)紅的錯(cuò)誤呢?declare module

          // typing.d.ts
          declare module 'visual-array'

          這樣報(bào)紅就消失了。

          typescript如何約束Promise的類型?

          Promise泛型函數(shù)


          interface Promise<T> {
          then<TResult1 = T, TResult2 = never>(onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null): Promise<TResult1 | TResult2>;
          catch<TResult = never>(onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null): Promise<T | TResult>;
          }
          interface foo {
          bar: ()=>Promise<string>,
          baz: ()=>Promise<number[]>,
          car: (id)=>Promise<boolean[]>
          }

          typescript中的keyof如何使用?

          最簡

          type Point = { x: number; y: number };
          type P = keyof Point; // 'x' | 'y'
          let foo: P = 'x';
          let bar: P = 'y';
          let baz: P = 'z'; // ?

          常用

          interface Person {
          name: string;
          age: number;
          location: string;
          }
          type K1 = keyof Person; // "name" | "age" | "location"
          type K2 = keyof Person[]; // "length" | "push" | "pop" | "concat" | ...
          type K3 = keyof { [x: string]: Person }; // string

          type P1 = Person["name"]; // string
          type P2 = Person["name" | "age"]; // string | number
          type P3 = string["charAt"]; // (pos: number) => string
          type P4 = string[]["push"]; // (...items: string[]) => number
          type P5 = string[][0]; // string

          keyof使得函數(shù)類型安全(type-safe)

          function getProperty<T, K extends keyof T>(obj: T, key: K) {
          return obj[key]; // Inferred type is T[K]
          }
          function setProperty<T, K extends keyof T>(obj: T, key: K, value: T[K]) {
          obj[key] = value;
          }
          let x = { foo: 10, bar: "hello!" };
          let foo = getProperty(x, "foo"); // number
          let bar = getProperty(x, "bar"); // string
          let oops = getProperty(x, "wargarbl"); // Error! "wargarbl" is not "foo" | "bar"
          setProperty(x, "foo", "string"); // Error!, string expected number

          Partial,Required,Readonly,Pick 泛型工具類型的實(shí)現(xiàn)原理

          type Partial<T> = {
          [P in keyof T]? : T[P];
          }
          type Required<T> = {
          [P in keyof T]?- : T[P];
          }
          type Readonly<T> = {
          readonly [P in keyof T] : T[P];
          }
          type Pick<T, K extends keyof T> = {
          [P in K]: T[P]
          }

          typescript中的typeof如何使用?

          js中的typeof主要用于表達(dá)式上下文,而ts中的typeof主要用于類型上下文。

          let s = "hello";
          let n: typeof s;
          // ^ = let n: string
          type Predicate = (x: unknown) => boolean;
          type K = ReturnType<Predicate>;
          // ^ = type K = boolean
          function f() {
          return { x: 10, y: 3 };
          }
          type P = ReturnType<typeof f>;
          // ^ = type P = {
          // x: number;
          // y: number;
          // }

          typescript中的non-null assert operator是什么?

          非null斷言操作符:當(dāng)為null時(shí),發(fā)生斷言,拋出異常。可選鏈:當(dāng)為null/undefined時(shí),返回undefined。

          非空斷言操作符和可選鏈操作符測試

          // Non-Null Assertion Operator

          const obj = null;

          interface Entity {
          name?: string;
          }

          // 非空斷言操作符
          function nonNull(e?: Entity) {
          const s = e!.name; // 發(fā)生斷言,拋出TypeError
          }

          try {
          nonNull(obj);
          } catch (e) {
          console.error("nonNull catch", e); // TypeError: Cannot read property 'name' of null
          }

          // 可選鏈
          function optionalChaining(e?: Entity) {
          const s = e?.name;
          console.log(s); // undefined
          }

          optionalChaining(obj);

          用于函數(shù)返回值空檢測

          function returnNullFunc() {
          return null;
          }

          try {
          returnNullFunc()!.age;
          } catch (e) {
          console.error("returnNullFunc", e); // TypeError: Cannot read property 'age' of null
          }

          function returnNonNullFunc() {
          return {
          age: "18"
          };
          }
          returnNonNullFunc()!.age;

          在線demo:https://codesandbox.io/s/non-null-operator-6bcf4

          期待和大家交流,共同進(jìn)步:

          ?微信公眾號(hào):大大大前端 / excellent_developers?Github博客: 趁你還年輕233的個(gè)人博客[2]?SegmentFault專欄:趁你還年輕,做個(gè)優(yōu)秀的前端工程師[3]

          努力成為優(yōu)秀前端工程師!

          References

          [1] TypeScript入門: https://github.com/FrankKai/FrankKai.github.io/issues/105
          [2] 趁你還年輕233的個(gè)人博客: https://github.com/FrankKai/FrankKai.github.io
          [3] 趁你還年輕,做個(gè)優(yōu)秀的前端工程師: https://segmentfault.com/blog/chennihainianqing


          瀏覽 90
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  女人考逼久久久 | 婷婷五月天激情综合网 | 亚洲男女免费视频 | 国产免费又粗又大又硬又爽视频 | 日本午夜福利视频 |