10 Advanced TypeScript Tips for Development
https://levelup.gitconnected.com/10-advanced-typescript-tips-for-development-2666298d50f
1. keyof
keyof
is slightly similar to Object.keys
, except that keyof
takes the keys of the interface.
interface Point {
x: number
y: number
}
// type keys = "x" | "y"
type keys = keyof Point
Suppose we have an object
as shown below and we need to implement a get
function using typescript to get the value of its properties.
const data = {
a: 3,
hello: "max",
}
function get(o: object, name: string) {
return o[name]
}
We might have written it that way at first, but it has many drawbacks:
- Unable to confirm the return type: this will lose ts’ maximum type-checking capability
- Unable to constrain the key: may commit a spelling error
In this case, you can use keyof
to enhance the type
function of the get
function, for those who are interested, see the type tag of _.get
and its implementation.
function get<T extends object, K extends keyof T>(o: T, name: K): T[K] {
return o[name]
}
2. Required & Partial & Pick
Now that you know the keyof
, you can use it to do some extensions to the properties, such as implementing Partial
and Pick
, Pick
is generally used in _.pick
type Partial<T> = {
[P in keyof T]?: T[P]
}
type Required<T> = {
[P in keyof T]-?: T[P]
}
type Pick<T, K extends keyof T> = {
[P in K]: T[P]
}
interface User {
id: number
age: number
name: string
}
// Equivalent to: type PartialUser = { id?: number; age?: number; name?: string; }
type PartialUser = Partial<User>
// Equivalent to: type PickUser = { id: number; age: number; }
type PickUser = Pick<User, "id" | "age">
These types are built into Typescript.
3. Condition Type
It is similar to the ?: operator, you can use it to extend some basic types.
T extends U ? X : Y
type isTrue<T> = T extends true ? true : false
// Equivalent to type t = false
type t = isTrue<number>
// Equivalent to type t = false
type t1 = isTrue<false>
4. never & Exclude & Omit
the never type represents the type of values that never occur.
There are many interesting and useful types that can be introduced by combining never
and conditional
type, such as Omit
type Exclude<T, U> = T extends U ? never : T
// Equivalent to: type A = 'a'
type A = Exclude<"x" | "a", "x" | "y" | "z">
In combination with Exclude
, we can introduce Omit’s writing style
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>
interface User {
id: number
age: number
name: string
}
// Equivalent to: type PickUser = { age: number; name: string; }
type OmitUser = Omit<User, "id">
5. typeof
As the name implies, typeof represents a type that takes a certain value, and the following examples show their usage
const a: number = 3
// Equivalent to: const b: number = 4
const b: typeof a = 4
In a typical server-side project, we often need to stuff some tools into the context
, such as config, logger, db models, utils, etc., and then use typeof
.
import logger from "./logger"
import utils from "./utils"
interface Context extends KoaContect {
logger: typeof logger
utils: typeof utils
}
app.use((ctx: Context) => {
ctx.logger.info("hello, world")
// will return an error because this method is not exposed in logger.ts, which minimizes spelling errors
ctx.loger.info("hello, world")
})
6. is
Before that, let’s look at a koa
error handling process. Here is the process of centralizing the error
handling and identifying the code
app.use(async (ctx, next) => {
try {
await next()
} catch (err) {
let code = "BAD_REQUEST"
if (err.isAxiosError) {
code = `Axios-${err.code}`
} else if (err instanceof Sequelize.BaseError) {
}
ctx.body = {
code,
}
}
})
At err.code
, it will compile with an error that Property ‘code’
does not exist on type ‘Error’.ts(2339)
.
In this case, you can use as AxiosError
or as any
to avoid the error, but forced type conversion is not friendly enough!
if ((err as AxiosError).isAxiosError) {
code = `Axios-${(err as AxiosError).code}`
}
In this case, you can use is to determine the type of the value.
function isAxiosError(error: any): error is AxiosError {
return error.isAxiosError
}
if (isAxiosError(err)) {
code = `Axios-${err.code}`
}
In the GraphQL source code, there are many such uses to identify types.
export function isType(type: any): type is GraphQLType
export function isScalarType(type: any): type is GraphQLScalarType
export function isObjectType(type: any): type is GraphQLObjectType
export function isInterfaceType(type: any): type is GraphQLInterfaceType
7. interface & type
What is the difference between interface and type? You can refer here.
The difference between interface and type is very small, for example, the following two ways of writing are similar.
interface A {
a: number
b: number
}
type B = {
a: number
b: number
}
The interface
can be merged as follows, while the type
can only be linked using the & class.
interface A {
a: number
}
interface A {
b: number
}
const a: A = {
a: 3,
b: 4,
}
8. Record & Dictionary & Many
These syntactic sugars are learned from the types source code of lodash
, and are usually used quite frequently in the workplace.
type Record<K extends keyof any, T> = {
[P in K]: T
}
interface Dictionary<T> {
[index: string]: T
}
interface NumericDictionary<T> {
[index: number]: T
}
const data: Dictionary<number> = {
a: 3,
b: 4,
}
9. Maintaining the const table with const enum
Use objects to maintain consts
const TODO_STATUS {
TODO: 'TODO',
DONE: 'DONE',
DOING: 'DOING'
}
// Maintaining constants with const enum
const enum TODO_STATUS {
TODO = 'TODO',
DONE = 'DONE',
DOING = 'DOING'
}
function todos (status: TODO_STATUS): Todo[];
todos(TODO_STATUS.TODO)
10. VS Code Tips & Typescript Command
Sometimes with VS Code, the issues that arise when compiling with tsc
do not match the issues prompted by vs code
Find the words Typescript
in the bottom right corner of the project, the version number is shown on the right side, you can click on it and select Use Workspace Version
, it means that it is always the same as the typescript
version that the project depends on.
Or edit .vs-code/settings.json
{
"typescript.tsdk": "node_modules/typescript/lib"
}
In short, TypeScript increases the readability and maintainability of code and makes our development more elegant.