poremark
poremark

Reputation: 13

Can't assign object to literal types

  interface IOptions {
    foo: 'bar';
  }

  const example = (opts: IOptions) => console.log(opts);

  const options = { foo: 'bar' };

  example(options); // Argument of type '{ foo: string; }' is not assignable to parameter of type 'IOptions'. Types of property 'foo' are incompatible. Type 'string' is not assignable to type '"bar"'.
  example({ foo: 'bar' }); // runs fine

As you can see I passed same exact object, but if I define it first it's doesn't work for some reason.

Upvotes: 1

Views: 130

Answers (2)

Aleksey L.
Aleksey L.

Reputation: 37948

You've used string literal type for foo property:

foo: 'bar';

String literal types allow you to specify the exact value a string must have

This means that foo can hold only 'bar' value (not any string).

Type of options is resolved to { foo: string } because foo is mutable. If you want to force typescript to infer literal type, you can use as const assertion:

const options = { foo: 'bar' } as const; // type is { readonly foo: "bar"; }
example(options); // no error now

Another option is specifying the type explicitly:

const options: IOptions = { foo: 'bar' };

If you want to allow foo to accept any string, change the definition to:

interface IOptions {
  foo: string;
}

Upvotes: 1

Ashish
Ashish

Reputation: 4330

You need to define the type of options. Because just by defining the const it is not guaranteed that your defined will continue to have the same signature, you can add or remove keys at any point of time as it is not explicitly defined with any type it can raise an error.

interface IOptions {
    foo: 'bar';
}

const example = (opts: IOptions) => console.log(opts);

const options: IOptions = { foo: 'bar' }; // define type here
const options2 = { foo: 'bar' };

example(options); 
example(options2 as IOptions) // If you are sure that options 2 is correct type
example({ foo: 'bar' });

Upvotes: 0

Related Questions