2024-04-19
2232
#typescript
Simohamed Marhraoui
70024
Apr 19, 2024 ⋅ 7 min read

Understanding infer in TypeScript

Simohamed Marhraoui Vue and React developer | Linux enthusiast | Interested in FOSS

Recent posts:

How To Integrate WunderGraph With Your Frontend Application

How to integrate WunderGraph with your frontend application

Unify and simplify APIs using WunderGraph to integrate REST, GraphQL, and databases in a single endpoint.

Boemo Mmopelwa
May 17, 2024 ⋅ 5 min read
Understanding The Latest Webkit Features In Safari 17.4

Understanding the latest Webkit features in Safari 17.4

The Safari 17.4 update brought in many modern features and bug fixes. Explore the major development-specific updates you should be aware of.

Rahul Chhodde
May 16, 2024 ⋅ 10 min read
Using Webrtc To Implement Peer To Peer Video Streaming In A Node Js Project

Using WebRTC to implement P2P video streaming

Explore one of WebRTC’s major use cases in this step-by-step tutorial: live peer-to-peer audio and video streaming between systems.

Oduah Chigozie
May 16, 2024 ⋅ 18 min read
Htmx Vs React

htmx vs. React: Choosing the right library for your project

Both htmx and React provide powerful tools for building web apps, but in different ways that are suited to different types of projects.

Temitope Oyedele
May 15, 2024 ⋅ 9 min read
View all posts

6 Replies to "Understanding <code>infer</code> in TypeScript"

  1. A literal [ ‘hello’ , ‘world’ ] in Typescript code is by default typed as a mutable array not a readonly tuple, but you can resolve this with `as const`.

    Although it was a two-arg string array when you created it, Typescript models it as a mutable array, because you could push(), pop() and so on. One way to defeat this type-widening, alex should be declared `as const` which prevents it from being considered mutable and makes push(), pop() a compiler error so it can never vary from being a two-value tuple.

    I really liked the learning associated with infer, (for when you can’t edit the function), but for the case where you can edit the function, I think a better fix is for the person type to be asserted readonly in the first place and to use `as const` when composing person objects, which allows the original code to compile…

    function describePerson(person: Readonly<{
    name: string;
    age: number;
    hobbies: Readonly; // tuple
    }>) {
    return `${person.name} is ${person.age} years old and love ${person.hobbies.join(” and “)}.`;
    }

    const alex = {
    name: ‘Alex’,
    age: 20,
    hobbies: [‘walking’, ‘cooking’] // type is [string, string]
    } as const;

    describePerson(alex)

    Getting this right means that you haven’t type-widened the alex object, to turn e.g. hobbies into [string,string] by declaring it as a Person. When you use `as const` the hobbies property can still be inferred by the editor as being the narrower [‘walking’,’cooking’]. This has saved me a million times where compiler and editor awareness of the values is needed to guard sensitive logic. For example, some other type might be {hobby:’cooking’|’walking’, favouriteOutdoorMeals:string[]} and the compiler can know that both values of alex.hobbies fulfil the hobby value. This is not possible after type-widening them to string.

    See also https://learntypescript.dev/10/l4-readonly-function-parameters and https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/prefer-readonly-parameter-types.md

    You can see the above approach in the playground https://www.typescriptlang.org/play?#code/GYVwdgxgLglg9mABAEwKYGcICcYCNUAKqW6CAFAA7GlgBciASqgIbIIA2AngDwDeAsAChEiMMwC2qeuig4wAcwDcQkc3lTRIcfizLhiABZxcuGBnpNWHHgG0Zc+QBpE9mAoC6APkWIA9L8QoEAp2VCEAX08ASkQBfSxUIKwkAAMAEl4qEgQAOjFJcMQYdEQMrJoctVRCzhYSRDh2ZERmMGb2OAA3VFLM6lyjEzN0HIArODcyACIWtpEpqPCclL1woSEIBBkW0IAPRABeWJVRCQ0AcgBBPfPHE6r6ACYABjv9QdNzRBtzgHdmdgAazc8luiHOmzgwIU53cfgCUE4VCKJTsshBzlcHgiLRKmzAMj0QjQmBw+CI2TAZABqF2USAA

  2. Thank you so much for this great article. I didn’t get a sense of “infer” from official TS guide. But here it described perfectly

  3. This is so COOL! This article let me understand the concept of ‘infer’. Thanks a lot, Marhraoui 🙂

  4. For you who need to infer Function return Promise,

    type PromiseReturnType = T extends Promise ? Return : T
    type FunctionReturnType = T extends (…args: any[]) => infer R
    ? PromiseReturnType
    : any

Leave a Reply