I have been using TypeScript for a year, and the technology used in the project is Vue + TypeScript. I feel the necessity of TypeScript in medium and large projects, especially in large projects with long life cycle.

The following are some of the TypeScript techniques I’ve used frequently in my work.

1. The comments

A comment of the form /** */ can be used to indicate the TS type. The editor will have a better indication:

/** This is a cool guy. */
interface Person {
  /** This is name. */
  name: string,
}

const p: Person = {
    name: 'cool'
}
Copy the code

This is a great way to add comments or friendly hints to a property.

2. Interface inheritance

Like classes, interfaces can inherit from each other.

This allows us to copy members from one interface to another, giving us more flexibility to split the interface into reusable modules.

interface Shape {
    color: string;
}

interface Square extends Shape {
    sideLength: number;
}

let square = <Square>{};
square.color = "blue";
square.sideLength = 10;
Copy the code

An interface can inherit multiple interfaces to create a composite interface of multiple interfaces.

interface Shape {
    color: string;
}

interface PenStroke {
    penWidth: number;
}

interface Square extends Shape, PenStroke {
    sideLength: number;
}

let square = <Square>{};
square.color = "blue";
square.sideLength = 10;
square.penWidth = 5.0;
Copy the code

3. interface & type

TypeScript defines types in two ways: interfaces and type aliases.

For example, in the following Interface and Type alias examples, except for the syntax, the meaning is the same:

Interface

interface Point {
  x: number;
  y: number;
}

interface SetPoint {
  (x: number, y: number): void;
}
Copy the code

Type alias

type Point = {
  x: number;
  y: number;
};

type SetPoint = (x: number, y: number) = > void;
Copy the code

Both are extensible, but the syntax is different. Also, note that interface and type aliases are not mutually exclusive. Interfaces can extend type aliases and vice versa.

Interface extends interface

interface PartialPointX { x: number; }
interface Point extends PartialPointX { y: number; }
Copy the code

Type alias extends type alias

type PartialPointX = { x: number; };
type Point = PartialPointX & { y: number; };
Copy the code

Interface extends type alias

type PartialPointX = { x: number; };
interface Point extends PartialPointX { y: number; }
Copy the code

Type alias extends interface

interface PartialPointX { x: number; }
type Point = PartialPointX & { y: number; };
Copy the code

The differences can be seen in the following diagram or in TypeScript: Interfaces vs Types.

So 檙 is not easy to skillfully use interface & Type.

If you don’t know what to use, remember: if you can use interface, use interface; if not, use type.

4. typeof

The typeof operator can be used to get the typeof a variable or object.

We usually define the type first, then use:

interface Opt {
  timeout: number
}
const defaultOption: Opt = {
  timeout: 500
}
Copy the code

Sometimes it can be reversed:

const defaultOption = {
  timeout: 500
}
type Opt = typeof defaultOption
Copy the code

When an interface always has a literal initial value, consider this method to reduce code duplication by at least two lines

5. keyof

TypeScript allows us to iterate over a type of property and extract its name through the keyof operator.

The keyof operator, introduced in TypeScript 2.1, can be used to get all keys of a type whose return type is a union type.

Keyof is slightly similar to object. keys, except that keyof takes the keyof interface.

const persion = {
  age: 3.text: 'hello world'
}

// type keys = "age" | "text"
type keys = keyof persion;
Copy the code

This is what a normal person might do when writing a method that gets the value of an attribute in an object

function get1(o: object, name: string) {
  return o[name];
}

const age1 = get1(persion, 'age');
const text1 = get1(persion, 'text');
Copy the code

But it will prompt you with an error

There is no pre-declared key in object.

Of course, if you change o: object to o: any, you will not get an error, but you will get a value that has no type and will become any.

You can use keyof to enhance the type function of the get function. If you are interested, you can see the type tag of _

function get<T extends object.K extends keyof T> (o: T, name: K) :T[K] {
  return o[name]
}
Copy the code

6. Find the type

interface Person {
    addr: {
        city: string,
        street: string,
        num: number,
    }
}
Copy the code

When you need to use the type of addr, in addition to the type out

interface Address {
    city: string,
    street: string,
    num: number,
}

interface Person {
    addr: Address,
}
Copy the code

You can also

Person["addr"] // This is Address.
Copy the code

Such as:

const addr: Person["addr"] = {
    city: 'string'.street: 'string'.num: 2
}
Copy the code

In some cases the latter makes code cleaner and easier to read.

7. Find type + generic + keyof

Generics is the property of defining functions, interfaces, or classes without specifying a specific type in advance, but specifying the type at the time of use.

interface API {
    '/user': { name: string },
    '/menu': { foods: string[] }
}
const get = <URL extends keyof API>(url: URL): Promise<API[URL]> => {
    return fetch(url).then(res => res.json());
}

get('');
get('/menu').then(user => user.foods);
Copy the code

Type assertion

Vue components often use ref to obtain attributes or methods of subcomponents, but often can not infer what attributes and methods, and will report errors.

Child components:

<script lang="ts">
import { Options, Vue } from "vue-class-component";

@Options({
  props: {
    msg: String,}})export default class HelloWorld extends Vue { msg! : string; }</script>
Copy the code

The parent component:

<template>
  <div class="home">
    <HelloWorld
      ref="helloRef"
      msg="Welcome to Your Vue.js + TypeScript App"
    />
  </div>
</template>

<script lang="ts">
import { Options, Vue } from "vue-class-component";
import HelloWorld from "@/components/HelloWorld.vue"; // @ is an alias to /src

@Options({
  components: {
    HelloWorld,
  },
})
export default class Home extends Vue {
  print() {
    const helloRef = this.$refs.helloRef;
    console.log("helloRef.msg: ", helloRef.msg); 
  }

  mounted() {
    this.print(); }}</script>
Copy the code

This.$refs.helloRef is an unknown type.

Make a type assertion:

  print() {
    // const helloRef = this.$refs.helloRef;
    const helloRef = this.$refs.helloRef as any;
    console.log("helloRef.msg: ", helloRef.msg); // helloRef.msg: Welcome to Your Vue.js + TypeScript App
  }
Copy the code

But type assertions of any are bad. If you know the specific type, write the specific type, otherwise there seems to be no point in importing TypeScript.

Explicit generics

$(‘button’) is a DOM element selector, but the type of the value returned is run-time determined

function $<T extends HTMLElement> (id: string) :T {
    return (document.getElementById(id)) as T;
}

// Not sure about the input type
// const input = $('input');

// Tell me what element it is.
const input = $<HTMLInputElement>('input');
console.log('input.value: ', input.value);
Copy the code

Function generics do not have to automatically derive the type, sometimes it is good to specify the type explicitly.

10. DeepReadonly

Attributes marked by readonly can only be assigned at declaration time or in the constructor of a class.

After that, it will not be modifiable (that is, read-only), otherwise a TS2540 error will be thrown.

Much like const in ES6, but readOnly can only be used on properties in classes (or interfaces in TS). It is a syntactic sugar for properties that have only getters but no setters.

Implement a deep declaration of readonly:

type DeepReadonly<T> = {
  readonly [P in keyof T]: DeepReadonly<T[P]>;
}

const a = { foo: { bar: 22}}const b = a as DeepReadonly<typeof a>
b.foo.bar = 33 // Cannot assign to 'bar' because it is a read-only property.ts(2540)
Copy the code

The last

Hey, guys, give me a thumbs up if you think it’ll help.

Did not write original technical article for quite a long time, as the first original technical article of 2021, the quality should still be ok 😅

Here is my year-end summary: Front-end Engineer’s year-end summary for 2020 – the world is still in the balance, and I hope to give you some inspiration.

Reference article:

  • TypeScript advanced techniques
  • Use opportunely Typescript
  • Working with Typescript (2)
  • interface