Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Type '{}' is not assignable to type 'T'

Tags:

typescript

function f1<T extends {[prop: string]: any}}>(a: T = {}) {
    console.log(a)
}

Error: Type '{}' is not assignable to type 'T'.

im trying to give a a default value. im not trying to give T a default type.

I'm not sure what is the problem.

like image 750
Stav Alfi Avatar asked Jun 25 '19 08:06

Stav Alfi


1 Answers

Consider the following example

type A = { [prop: string]: any };
type B = { [prop: string]: any; prop1: string };

Does type B extend type A? Yes!

But the following will not work

let a: A = {};
let b: B = a; // Error

It's clear that type A misses required property prop1, so variable a is not assignable to variable b.

The same issue is with your function. When you do

function f1<T extends { [prop: string]: any }>(a: T = {}) {
    console.log(a);
}

Compiler says that object {} is not assignable to type T. If this worked, you could do

f1<B>();  // a will equal to {} and misses required prop1

This may not look like error, as inside f1 you only know that T extends { [prop: string]: any } and know nothing about prop1. But consider if you want return T:

function f1<T extends { [prop: string]: any }>(a: T = {}): T {
    console.log(a);
    return a;
}

If this code would work it would introduce a bug

let bb: B = f1<B>();  // Here bb will be equal to empty object
let s: string = bb.prop1;  // Compiler will not show error, as it thinks that bb has prop1 of type string. But in reality it is undefined.

So there are following solutions to consider:

  1. Remove all generics. Type { [prop: string]: any } is generic by itself so it may suit your needs

    function f1(a: { [prop: string]: any } = {}) {
        console.log(a);
        return a;
    }
    
  2. Make a fully optional. In this case a may equal to undefined and compiler would know about it.

    function f1<T extends { [prop: string]: any } = {}>(a?: T) {
        console.log(a);
    }
    

    If you return a compiler will tell you that you should either return union type (with undefined) or check in function body that a is not undefined.

  3. Worst case from my point of view is to use type cast as already suggested

    function f1<T extends { [prop: string]: any }>(a: T = {} as T) {
        console.log(a);
    }
    

    But be careful and don't forget that you can miss some required properties in this case.

like image 80
Fyodor Avatar answered Oct 10 '22 23:10

Fyodor