Skip to content

Instantly share code, notes, and snippets.

@Jack-Works
Last active November 12, 2020 15:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Jack-Works/25a1f69d50a444093853bcc069849081 to your computer and use it in GitHub Desktop.
Save Jack-Works/25a1f69d50a444093853bcc069849081 to your computer and use it in GitHub Desktop.
FAQ: Why TypeScript is correct? / Why TypeScript cannot express this?

Frequently asked TypeScript question

I think my code is correct! Why it is complaining type error to me?

How can I do something in TypeScript?

Case 1: Add function

function add<T extends number | bigint>(left: T, right: T): T {
    return left + right
}

TS2365: Operator '+' cannot be applied to types 'T' and 'T'.

Explain: Consider this code:

add<number | bigint>(1, 2n)

This call is valid but it will cause a runtime error therefore TypeScript is correct to give the error in the implementation of add.

Because in TypeScript you cannot require the generics T is a "concrete" type that only can be "number" or "bigint" but not "number | bigint", therefore this error is not a false-positive.

One of the correct way to implement an add function is:

const add: {
  (x: number, y: number): number
  (x: bigint, y: bigint): bigint
} = ((a: any, b: any) => a + b) as any

add(1, 2) // ok
add(1n, 2n) // ok
add(1, 2n) // error

Case 2: Incompatible index signatures

How to write a type that have index signatures with incompatible named properties?

interface T {
    // @ts-ignore
    name: string
    [index: string]: number
}

Explain:

When looking up properties on a type, TypeScript first find if there is matching named properties, in this case, name. If there is not, the compiler will try to lookup if there is index signature.

Without @ts-ignore the compiler will report "string" is not assignable to "number" but that error doesn't make type T becomes any. By ignoring the error, we create a type that have incompatible signatures.

To create an instance of this type, you will need to use as any because when assigning, the compiler first check if name is matching string (the named signature), then also check if it is matching the index signature (number in the case) which is not possible.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment