Type Inference Core Principles

Pro Members Only

This lesson is available if you have an active subscription.

Alternatively, some member might be able to gift it to you.

If you already have a subscription, you can sign in.

Type Inference Core Principles

Subscription Required

You must have an active subscription to access this content.
If you already have a subscription, you can sign in.

Assignment Inference

const x = 123;

let y = 123;

let z = 123 as const;

const alpha = {
name: 'alpha',
};

const beta = {
name: 'beta',
} as const;

Function Return Inference

function simple() {
return Math.random();
}

function multi() {
return Math.random() > 0.5 ? 'win' : 0;
}

Function Assignment Inference

type NumToNum = (value: number) => number;

const func: NumToNum = (value) => value;

function invoke(cb: NumToNum) {
return cb(0);
}
invoke((value) => value);

let props: { onRender: NumToNum } = {
onRender: (value) => value,
};
javascript
typescript
react
playwright

Enjoy free content straight from your inbox 💌

No spam, unsubscribe at any time.

Transcript

00:00

Over time as TypeScript has evolved, it has constantly improved the types that it infers without you needing to manually add type annotations. However, the underlying core flows of inference is the same since I discussed them with the TypeScript team in 2014. So let's take a look at these principle ways that TypeScript can automatically infer the types present in your code. The simplest form of inference that exists within TypeScript is when an assignment takes place for a newly created variable. What type will get inferred will depend upon a number of factors. For example, is it a cons versus a let? This particular variable is a cons

00:32

and what value is being assigned here. A primitive value is being assigned, and numbers in cript are immutable, and since this is a Constable, TypeScript infers the literal type 1, 2, 3. If you repeat the same example with a lead declaration, TypeScript infers a more loose type, which is number because Y can be potentially reassigned. We can actually ask TypeScript to be more strict in its inference despite using let by using the S constant assertion, which we previously looked at in its own dedicated lesson. A variable definition inference of course also works for object types, but it is simply a combination

01:06

of the inferred types of the different members. Now, of course, by default, TypeScript will be a bit loose with object inference as well because as an example, alpha name can be reassigned. Therefore alpha name is inferred to be a string instead of the literal alpha. We can actually make it more strict by using the S cost assertion. For example, beta name over here is inferred to be exactly the literal beta and read only as well, so that it cannot be assigned something else. Another kind of inference in TypeScript is the function return type inference. When you think about it, a function return value is not

01:38

that different from a variable initializer. The key difference is that a function might commonly have multiple return parts, in which case TypeScript will try to combine the types as much as possible. Consider a simple function where we are not annotating the return type, and instead within the function body we are returning Mastro. Random TypeScript will automatically infer the return type for the simple function based on the return type of Mastro random, which itself is of type number. Another example would be a function that has multiple kinds of returns. For example, here we are either returning the string win or the number zero.

02:12

In this particular case, TypeScript infers the return type of this multifunction to be the union of the literal win or the literal zero. One commonly overlooked form of inference and TypeScript is the inference of the function inputs and outputs based on us assigning the function definition to a variable of a particular type. Consider the declaration of a function type num to num, which is a function that takes a value of type number and must return a number. If you assign a function to a variable which is declared to be type, num to num. We don't need to annotate the function because input is going

02:44

to be inferred based on the type definition. In this particular case, value is inferred to be of type number and the return type is also going to be enforced. So if you return something other than a number, TypeScript put complaint, and we've already discussed that function arguments are essentially a Form of variable assignment. Therefore, if you have a function that takes a callback of type num to numb and we pass a function in line, the types for this particular function are also going to be inferred, and the same is going to be true for any other assignment with the type of the function can be inferred. For example, hey, we have an object

03:16

that has an on render method and since on render is marked to be of tight, nu to numb. We don't need to annotate it when we define it in line because it can be inferred from the object type. One final thought that I want to leave you with is that even though Ty Strip can infer a lot of things on its own, don't be shy of adding annotations to be explicit about your intent as it will still help the next person reading your code, which just might happen to be your future self.