2024-10-21
1777
#typescript
Simohamed Marhraoui
70024
Oct 21, 2024 ⋅ 6 min read

Understanding infer in TypeScript

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

Recent posts:

Container queries in 2026: Powerful, but not a silver bullet

Container queries let components respond to their own layout context instead of the viewport. This article explores how they work and where they fit alongside media queries.

Sebastian Weber
Dec 26, 2025 ⋅ 12 min read
Server Components Vs Islands Architecture LogRocket

Server Components vs. Islands Architecture: The performance showdown

React Server Components vs Islands Architecture: Learn how each reduces client JavaScript, impacts hydration and interactivity, and which trade-offs matter for production performance.

Muhammed Ali
Dec 26, 2025 ⋅ 4 min read

How to build agentic AI when your data can’t leave the network

Large hosted LLMs aren’t always an option. Learn how to build agentic AI with small, local models that preserve privacy and scale.

Rosario De Chiara
Dec 23, 2025 ⋅ 5 min read
frontend wrapped top stories of 2025

Frontend Wrapped 2025: The 10 storylines that defined the year

What storylines defined 2025 in frontend development? We power rank them all, from AI advancements to supply chain attacks and framework breakthroughs.

Chizaram Ken
Dec 23, 2025 ⋅ 6 min read
View all posts

8 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

  5. “`
    function getFirst(arr: T): T extends [infer U, …unknown[]] ? U : never {
    return arr[0];
    }

    const firstNumber = getFirst([1, 2, 3]); // firstNumber is inferred as number
    const firstString = getFirst([‘a’, ‘b’, ‘c’]); // firstString is inferred as string
    “`
    This example is not working in TS Playground. Both variables get `never`.

    1. Hey Serg! Thanks for letting us know. We contacted the writer, and he updated the code snippet and its explanation.

Leave a Reply

Hey there, want to help make our blog better?

Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.

Sign up now