This article summarizes TypeScript type declaration writing. In many cases, TypeScript writing is not a problem, but TypeScript writing is particularly difficult. Let me summarize some of the problems I have with TypeScript. If you encounter type declarations that don’t work, take a look at loDash’s declarations, because LoDash does all sorts of manipulation on the data, so you’ll find examples.
Basic types of
/ / variable
const num: number = 1;
const str: string = 'str';
const bool: boolean = true;
const nulls: null = null;
const undefine: undefined = undefined;
const symbols: symbol = Symbol('symbal');
const any: any = 'any types'; The typescript any type has no type constraints
Copy the code
An array of
// Array: T[] is recommended
const nums: number[] = [1.2.3.4];
// Not recommended: Array
is generic. It is incompatible with JSX, so T[] is used for consistency
const strs: Array<string> = ['s'.'t'.'r'];
const dates: Date[] = [new Date(), new Date()];
Copy the code
Array concat method, return type never[] problem
// Array concat method never problem
// prompt: Type 'string' is not assignable to Type 'never'.
const arrNever: string[] = [].concat(['s']);
// The main problem is: [] array, ts cannot determine the type of elements in the array according to the context
// @see https://github.com/Microsoft/TypeScript/issues/10479
const fixArrNever: string[] [] = (as string[]).concat(['s']);
Copy the code
interface
Interfaces are a core component of TypeScript, which can merge multiple type declarations into one:
And interfaces can be used to declare data types such as functions, classes, and objects
interface Name {
first: string;
second: string;
}
let username: Name = {
first: 'John',
second: 'Doe'
};
Copy the code
Any, NULL, undefined, void
// Special type
const any: any = 'any types'; // Typescript any type, equivalent to writing nothing at all
let nobody: any = 'nobody, but you';
nobody = 123;
let nulls: number = null;
let bool: boolean = undefined;
// void
function printUsername (name: string) :void {
console.log(name);
}
Copy the code
The joint type
Joint type in option bags very practical model scene, marked by using | * * * *
function options(opts: { types? :string;
tag: string | number;
}) :void {}Copy the code
Cross type
The most typical usage scenarios are inheritance and mixins, or operations such as copy
// Assign: If you can't write this type in the future, just look at object. assign
function $extend<T.U> (first: T, second: U) :T & U {
return Object.assign(first, second); // Just a hint
}
Copy the code
Tuples tuple
Tuples are rarely used
let nameNumber: [string.number];
// Ok
nameNumber = ['Jenny'.221345];
// Error
// nameNumber = ['Jenny', '221345'];
let tuple: [string.number];
nameNumber = ['Jenny'.322134];
const [usernameStr, uselessNum] = nameNumber;
Copy the code
The type of role
You can also rename (alias) existing types. It is recommended to use type to create simple types, unnested types, or a layer of nested types. Other complex types should be implemented using interface, combined with implements and extends.
type StrOrNum = string | number;
/ / use
let sample: StrOrNum;
sample = 123;
sample = '123';
// Check the type
sample = true; // Error
Copy the code
Problems encountered in practice
The third party library does not provide the declaration D. ts file
If a third-party library does not provide declaration file, the first time to https://github.com/borisyankov/DefinitelyTyped for the Microsoft’s official warehouse, or on npmjs.com search @ types/dependent module name most cases can be found.
-
Add the declaration file manually
Declaration files are generally placed in the types folder
// Example: types/axios.d.ts declare module'axios'; // Axios is declared to be of type anyCopy the code
The global variable
For example, some libraries simply add global variables to a window
// globals.d.ts
// Example: jQuery. In real life, jQuery has.d.ts
declare const jQuery: any;
declare const $: typeof jQuery;
Copy the code
The JavaScript resources
In front-end engineering, when importing many non-JS resources, such as CSS, HTML, images and VUE, which cannot be recognized by TS, it is necessary to tell TS how to identify the types of imported resources.
// See how vue handles this: shims-vue.d.ts
declare module '*.vue' {
import Vue from 'vue';
export default Vue;
}
// html
declare module '*.html';
// css
declare module '*.css';
Copy the code
Cast casting
Sometimes casts are needed, especially for associated types or optional attributes.
// First: use <> parentheses
const convertArrType: string[] = <Array<string>>[].concat(['s']);
// Use the as keyword
const fixArrNever: string[] [] = (as string[]).concat(['s']);
Copy the code
I recommend using the second one because it is compatible with JSX, and the first one is officially not recommended even though it is legal.
Optional and default properties
Many of the parameters provided in the API have default values or optional attributes.
class Socket {}
// Union type
export type SocketType = 'WebSocket' | 'SockJs';
export interface SocketOptions {
type: SocketType; protocols? :string | string[]; / / is optional
pingMessage: string | (() = >string); // Union type, which can bestringOr functionpongMessage: string | (() = >string); } // Default valueexport function eventHandler = (
evt: CloseEvent | MessageEvent | Event,
socket: Socket,
type = 'WebSocket' / / the default value
) = > any;
Copy the code
How do independent functions declare their types
I struggled with this at first, because I’m just a separate function, so how do I declare a type? Especially when writing apis for event handlers.
class Socket {}
// How a function is declared
export type SocketEventHandler = (
evt: CloseEvent | MessageEvent | Event,
socket: Socket
) => any;
const eventHandler: SocketEventHandler = (evt, socket) = >{}// Optional arguments and REST arguments
let baz = (x = 1) = > {};
let foo = (x: number, y: number) = > {};
let bar = (x? :number, y? :number) = > {};
let bas = (. args:number[]) = > {};
Copy the code
Index attribute type declaration
Objects in JavaScript can use string indexes to fetch properties or call methods directly, and TypeScript has type-declaration methods.
type Hello = {
hello: 'world';
// Key is just a formal attribute name (like a parameter)
[key: string] :string;
};
const greeting: Hello = {
hi: 'morning'
}
console.log(greeting['hi'])
Copy the code
Dynamically added property declarations
Sometimes we just declare a basic type structure, and then we extend it, especially options in secondary encapsulation.
interface AxiosOptions {}
type AjaxOptions = {
axiosOptions: AxiosOptions;
// Add additional extensions to separate attribute nodes
extraOptions: {
[prop: string] :any
};
};
typeAjaxOptions1 = { axiosOptions? : AxiosOptions;// Don't do this, because TS will not tell you when axiosOptions is misspelled
// Try to move subsequent extended attributes under separate attribute nodes
[prop: string] :any
};
const ajaxOptions: AjaxOptions1 = {
axiosOptions1: {}; // It is meant to be axiosOptions, but ts does not prompt
}
Copy the code
! The use of
! The identifier tells the TS compiler that there is no problem with the declared variable and that no errors will be reported during re-run.
class BaseSelect extends Vue {
options: string[]; // No initialization was done in constructor
created() {
this.options = ['inited']}}class BaseSelect extendsVue { options! :string[]; / / use! Tell the compiler I know what I'm doing, okay
created() {
this.options = ['inited']}}Copy the code
The use of this
For functions that are used independently, you can declare a specified calling context
class Handler {
info: string;
// Declare the specified this context
onClickBad(this: Handler, e: Event) {
// oops, used this here. using this callback would crash at runtime
this.info = e.message; }}let h = new Handler();
uiElement.addClickListener(h.onClickBad); // error!
Copy the code
Declaration merge (extending Vue declaration)
Take a look at the usage scenarios, extending the VUE, adding global attributes to the VUE.
// Vue is declared in vue/types/vue.d.ts
declare module 'vue/types/vue' {
$eventBus = Vue.$eventBus
interface Vue {
$eventBus: Vue;
}
// equivalent to Vue. Prototype.$eventBus
interfaceVueConstructor { $eventBus: Vue; }}Copy the code
Ignore TypeScript validation
Use // @ts-check to opt in to type checking for a single file.
Use // @ts-nocheck to opt out of type checking for a single file.
Use // @ts-ignore to opt out of type checking for a single line.
Copy the code
conclusion
There are many more advanced uses of TypeScript declarations that I don’t currently use that much. When I’m struggling with how to write a declaration, I look at how other people’s declaration files are written.
Note: try not todeconstructionandThe statementWritten together, it is very unreadable.
class Node {
onNodeCheck(checkedKeys: any, { / / deconstruction
checked, checkedNodes, node, event,
} : { / / declare
node: any;
[key: string] :any; }) {}}Copy the code
Pay attention to the public number, find more wonderful content.