3

What difference between these two functions? Both work the same. I know how extends work in interfaces but I can't understand the differences here

const func = <T extends string>(str: T): T => str 
const func = <T = string>(str: T): T => str 
Nick
  • 383
  • 1
  • 4
  • 16
  • "*Both work the same.*" no, they don't at all. `extends X` places a restriction on the generic - it has to be assignable to `X`. While `= X` just means that the default generic value, if not explicitly passed in or inferred, would be `X`. It doesn't restrict anything. You can call the second one as `func(42)` but not the first one. – VLAZ Mar 16 '22 at 18:03
  • Does this answer your question? [typescript generic type with equal operator means?](https://stackoverflow.com/questions/56843790/typescript-generic-type-with-equal-operator-means) and [Typescript generic type parameters: T vs T extends {}](https://stackoverflow.com/q/61648189) – VLAZ Mar 16 '22 at 18:04

1 Answers1

6

These are very different things.


<T extends string>

This is a constraint. This means that T must be string or a subtype of string (i.e. a string literal)

const func = <T extends string>(str: T): T => str

func("A") // returns type "A" because "A" is a subtype of string
func<string>("A") // returns type string because the inference was overridden
func(123) // error 123 is not a subtype of string

Playground


<T = string>

This is a default type. In this case T is not constrained, but if omitted string is used as the type of T.

const func = <T = string>(str: T): T => str

func("A") // returns type "A" because "A" is a inferred for T
func<string>("A") // returns type string because the inference was overridden
func(123) // returns type 123 because 123 is inferred as the type for T

Playground

The default type doesn't make a lot of sense in this example though since it is inferred by the argument when you omit it. So lets look at a different example:

type MyType<T = string> = { value: T }
type TestA = MyType<number> // equivalent to { value: number }
type TestB = MyType // equivalent to { value: string }

Playground

Note how in TestB you can leave out the generic, and the default of string is used instead.

However, in the case of T extends string both TestA and TestB are type errors:

type MyType<T extends string> = { value: T }
type TestA = MyType<number> // type error: number does not extend string
type TestB = MyType // type error: missing generic parameter

Playground

Alex Wayne
  • 178,991
  • 47
  • 309
  • 337
  • I have doubt in this line const func = (str: T): T => str and I dint found answer to it when I searched. My doubt is, why we need to put :T after (str:T) ? remaining part of the line I have understood. – dineshpandikona Oct 20 '22 at 06:42