Original link: Getting started with TypeScript

When I read the vue source code, I found TypeScript and was confused, so I needed to check in.

Recently, I also need to use TypeScript in my daily work in a new environment. I made a note of some doubts I encountered in the learning process.

Personally, I think it’s a good read for those who are getting started with TypeScript, because the same confusion I’ve encountered may be yours.

  • Of the TS type? What does <> mean?
  • What is duck typing?
  • What is the variable definition before constructor?
  • What is declare?
  • What is the difference between unknown, void, null and undefined?
  • What are the generic constraints in TS?
  • Two ways to define an array type
  • Type assertion in TS
  • Generic functions and generic interfaces
  • How to understand as const?
  • What does it mean to declare global?
  • How do I add a global variable to the TypeScript environment?
  • Can interfaces inherit?
  • What does & mean in typescript?
  • What is the difference between interface and type?
  • What does enum mean as a type?
  • What does xxx.D. TS declare Module ‘*.scSS ‘mean in the project?declare moduleWhat else can you do?
  • How does typescript constrain the types of promises?
  • How is keyof used in typescript?
  • How is Typeof used in typescript?
  • In the typescriptnon-null operatorWhat is?

Of the TS type? What does it mean?

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

This is a concept in ts interface. The ts interface is “duck typing” or “structural subtyping”, where type checking focuses on the shape that values have. So let’s get familiar with the interface, okay? The explanation.

TypeScript defines functions in a normal way:
function print(obj: {label: string}) {
    console.log(obj.label);
}
let foo = {size: 10.label: "This is Foo, 10 pounds."};
print(foo);
Copy the code
TypeScript interface defines functions:
interface labelInterface {
    label: string;
}
function print(obj: labelInterface) {
    console.log(obj.label);
}
let foo = {size: 10.label: "This is Foo, 10 pounds."};
print(foo);
Copy the code

Let’s get down to business. What’s in TypeScript? What does that mean? Optional Properties.

Optional Properties
  • Not all attributes in an interface are required, some exist under certain conditions, and some do not exist at all.
  • Optional Properties applies to the “Option Bags” design pattern, which means we pass an object to a function that has only a few Properties and no other Properties.
  • The nice thing about Optional Property is that you can clearly see what properties there are, so you can’t pass in properties that don’t belong to the 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"});
Copy the code

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.

What is? And Optional Properties? To the end of some non-required attribute names of the interface, add? This is an optional property, which literally means conditional property.

The Optional Property is just the name of the Property, options, okay? 😕 What is the question mark after “options” in “Object” and the question mark before “property value type”? What does “Object” mean? The question mark indicates whether the attribute value type can be null, but only if strictNullChecks is on can the value type be null.

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

In our example, options? 😕 Object means that options can be Object, null (only allowed if strictNullChecks is true).

In type TS<>What do you mean?

deps: Array<Dep>a
newDeps: Array<Dep>
Copy the code

Array types in TS are similar to those defined in Java:

let list: number[] = [1.2.3];
let list: Array<number> = [1.2.3];
Copy the code

What is duck typing?

Duck test. If “walks like a duck and quacks like a duck, then it’s a duck”. In computer programming, used to ‘determine whether an object can be used for its intended purpose’. In typical typing, applicability depends on the type of the object. In Duck typing, the suitability of an object depends on the presence or absence of a specified method or property, not on the type of the object itself.

Front-end engineers are mostly duck typing because JavaScript has no type. — I said it

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'`
Copy the code
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
Copy the code

What is the variable definition before constructor?

For example, the vnode definition:

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 nodesfnOptions: ? ComponentOptions;// for SSR cachingfnScopeId: ? string;// functional scope id support

  constructor ()... }Copy the code

www.typescriptlang.org/docs/handbo… Class in typeScript has one more item than es6: property. This is consistent with Java or c#.

property
constructor
method
Copy the code

In fact, ES6 provides a private variable that can only be accessed within a class.

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

What does VNode mean after the colon?

export function cloneVNode (vnode: VNode) :VNode {... }Copy the code

Functions in TypeScript return value types.

What is declare?

Declare this to be a definition.

  • Declare is the key used in TS to write definition files.
  • Declare can define global variables, global functions, global namespaces, classes, and more.
  • Declare can be used as follows:
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;
}
Copy the code

What is the difference between any, unknown, void, null and undefined?

Null, undefined means js.

Any: any type. Use caution to avoid typescript becoming anyscript unknown: similar to any, but more secure than any void: Never: never occur A type that never occurs, such as never having a result, throwing an exception, or an infinite loop.

What are the generic constraints in TS?

Based on string (Boolean, Function) type

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'.
Copy the code

Based on a custom 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
Copy the code

Ts2.8 Release notes

// 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"
Copy the code

Both type and interface generic constraints are supported

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
    // It is running properly
}

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

Copy the code

Two ways to define an array type

Array < type >

Array is followed by a <>, which declares the element type.

type Foo= Array<string>;
Copy the code
interface Bar {
     baz: ArrayThe < {name: string.age: number,} >}Copy the code

Type []

Element type followed by a [].

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

Type assertion in TS

TypeScript allows us to override inferred and parsed view types in any way we want. This mechanism is called Type Assertion. Type Assertion tells the compiler that you know what Type better than it does, so the compiler doesn’t have to make second inferences. Type assertions tend to occur during compilation to prompt the compiler to analyze our code.

  • grammar
  • Migrating JS code
  • Problem with type assertions
  • Specifying the event type
  • Be careful with as any and as unknown
  • Type and type assertion

grammar

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

let a:Foo = {} as Foo;
let a:Foo = {} as Any;
Copy the code

Any is a subtype of any type, so any type can be used as any, but caution is recommended to avoid anyscript.

Migrating JS code

var foo = {};
foo.bar = 123; // Error: property 'bar' does not exist on `{}`
foo.bas = 'hello'; // Error: property 'bas' does not exist on `{}`
Copy the code
interface Foo {
    bar: number;
    bas: string;
}
var foo = {} as Foo;
foo.bar = 123;
foo.bas = 'hello';  // Comment out this line without error
Copy the code

Problem with type assertions

foo.bas = ‘hello’; // If you comment out this line, there will be no error. If you comment out this line, there will be an error

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

For this reason, type assertions are not rigorous, and var foo: foo is recommended.

Specifying the event type

function handler (event: Event) {
    let mouseEvent = event as MouseEvent;
}
Copy the code
function handler(event: Event) {
    let element = event as HTMLElement; HTMLElement is not a complete event subtype, so it does not overlap enough. An unknown or any element is required
}
Copy the code

Secondary assertion compilation prompt cancelled:

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

Be careful with as any and as unknown

In general, type assertions S and T, where S is a subtype of T, or T is a subtype of S, are relatively safe. It is not safe to use as any or as unknown. Careful! Careful!

// Use caution
as any
as known
Copy the code

Type and type assertion

Type keys = ‘foo’ | ‘bar’ | ‘baz, obj [key as keys] is what mean? Similar to variable: Type, this is another type constraint.

If you don’t understand the flower, watch the following demo will understand.

type keys = 'foo' | 'bar' | 'baz'
const obj = {
    foo: 'a'.bar: 'b'.baz: 'c'
}
const test = (key:any) = > {
    return obj[key] ; Type 'any' can't be used to index type '{foo: string; bar: string; baz: string; } '.
}
Copy the code

How to resolve this error? The first way: type constraint

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

Second method: Type assertion (this method is commonly used in callback of third-party libraries where the return value type is not constrained)

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

Note: obj[key as keys] can have the type of keys less than obj, and obj cannot have the type of keys less than obj.

Generic functions and generic interfaces

Generic function

Consider a scenario where we want the input and output types of a function to be the same. You might do that, but it doesn’t guarantee that the input and output types will be the same.

function log(value: any) :any {
    return value;
}
Copy the code

This can be done precisely by adding a

to the function name, where T is understood as the name of the generic. Specifies that the input type is T and the return value is T.

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

This is an instance of a generic function. How do you define a generic function type?

type Log = <T>(value: T) = > T
Copy the code

Use generic function types to constrain functions:

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

A generic interface

All attributes of the interface are flexible and the input and output are consistent.

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

All attributes of an interface must be of the same type.

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

The ts<>

In TS, when <> is encountered, Angle brackets are mostly types.

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

How to understand as const?

  • To solve the let assignment problem, change a mutable variable to readonly.
  • Avoid extrapolating types to union types.

To solve the let assignment problem, change a mutable variable to readonly.

let x = "hello";
x = "world"; / / an error
Copy the code
The first is const
const x = "hello"
Copy the code
The second way is of the “hello” type
let x: "hello" = "hello";
x = "world"; // 
Copy the code
The third method is 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;
}
Copy the code
The fourth way is as const

. TSX type file

// 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;
Copy the code

A non-. TSX file

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

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

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

Optimize the 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); }}Copy the code

Avoid extrapolating types to union types.

Avoid type inference for (Boolean | typeof load) [], but the inference for Boolean, the 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)[]
}
Copy the code

What does it mean to declare global?

To make a declaration in the global namespace, such as adding an undefined attribute to an object.

Add CSRF definition for Window

declare global {
  interface Window {
    csrf: string; }}Copy the code

Add the definition of fancyFormat for String

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; }}Copy the code

Note that the global scope can only be used to export modules or external module declarations

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

How do I add a global variable to the TypeScript environment?

For example, if we wanted to implement the following effect, we would get an error Property ‘INITIAL_DATA’ does not exist

<script>
  window.__INITIAL_DATA__ = {
    "userID": "536891193569405430"
  };
</script>
const initialData = window.__INITIAL_DATA__; / / an error
Copy the code

Using type assertions

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

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

Declare global variables

declare var __INITIAL_DATA__: InitialData;
Copy the code
const initialData = __INITIAL_DATA__;
const initialData = window.__INITIAL_DATA__;
Copy the code

In the es module, which has import and export, we need to do this:

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

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

You can use a globals.d.ts file if you use it in many files.

Using interface merge

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

In a JS module you need something like this:

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

declare global {
  interface Window {
    __INITIAL_DATA__: InitialData; }}const initialData = window.__INITIAL_DATA__;
Copy the code

Can interfaces inherit?

You can.

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' })
Copy the code

When Props inherits from Base, it actually ends up like this:

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

Can Props override Base? Yes, but only required overrides optional, and optional does not override required.

/ / ✅interface Base { foo? : string; } interface Propsextends Base {
    foo: string; bar: string baz? : string }Copy the code
/ / ❌
interface Base {
    foo: string;
}

interface Props extendsBase { foo? : string; bar: string baz? : string }Copy the code

What does & mean in typescript?

There is a definition in the REACT DTS file.

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

The & in typescript refers to cross types.

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);
};
Copy the code

Now that ampersand is the crossover type in TS, we know what PropsWithChildren means and why the React function component has the children attribute more than the normal function component.

It means that PropsWithChildren type is P and object {children? The crossover type of: ReactNode}, where two objects are joined by &, results in an object with the children optional property.

What is the difference between interface and type?

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 can be inherited (with extends, for example), type cannot
  2. Interface can implement multiple merge declarations, type cannot

What does enum mean as a type?

In reading the pixi.js source code, I found that there is enum as a type.

Enum can also be constrained as a type.

// 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; / / best
        // this. BlendMode = 0
        // this.blendMode = ANOTHER_ENUM.FOO}}Copy the code

What does xxx.D. TS declare Module ‘*.scSS ‘mean in the project?declare moduleWhat else can you do?

What does xxx.D. TS declare Module ‘*.scSS ‘mean in the project?

// externals.d.ts
declare module '*.scss'
Copy the code

By default, import style from ‘style. SCSS ‘will fail in ts ide validators, so use d.ts to assume that the file that defines all SCSS endings is module. – President

If declare Module ‘*.scss’ is commented out, the IDE will report an error, but you can use Lint.

declare moduleWhat else can you do?

The IDE reports an error when we introduce a custom package that does not exist in Microsoft’s official @types/*.

For example:

How to solve the error of reporting red? declare module

// typing.d.ts
declare module 'visual-array'
Copy the code

So the reversion goes away.

How does typescript constrain the types of promises?

Promise generic functions


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>;
}
Copy the code
interface foo {
   bar: () = >Promise<string>,
   baz: () = >Promise<number[]>,
   car: (id) = >Promise<boolean[]>
}
Copy the code

How is keyof used in typescript?

The minimalist

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

The commonly used

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
Copy the code

Keyof makes functions 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
Copy the code

Partial, Required, Readonly, Pick a generic tool type the principle

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

How is Typeof used in typescript?

Typeof in JS is primarily used in expression context, while typeOF in TS is primarily used in type context.

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

In the typescriptnon-null assert operatorWhat is?

Non-null assertion operator: When null, assertion occurs and an exception is thrown. Optional chain: Returns undefined when null/undefined.

Non-empty assertion operator and optional chain operator tests

// Non-Null Assertion Operator

const obj = null; interface Entity { name? : string; }// Non-null assertion operator
function nonNull(e? : Entity) {
  consts = e! .name;// An assertion occurs, raising TypeError
}

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

/ / optional link chain
function optionalChaining(e? : Entity) {
  consts = e? .name;console.log(s); // undefined
}

optionalChaining(obj);
Copy the code

Null detection for function return value

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;Copy the code

IO /s/non-null-…

Looking forward to communicating with you and making progress together:

  • excellent_developers
  • Github blog: Personal blog 233 while You’re Still Young
  • SegmentFault column: Be a good front-end engineer while you’re still young

Strive to be an excellent front-end engineer!