TomPeters
TomPeters

Reputation: 157

Passing an interface as a type with index signature in typescript

I want to be able to pass interface into a certain function in typescript, where that function can accept any object type, so long as all of its properties are of a certain type.

Consider the following example:

function DoSomething(args: { readonly [propertyName: string]: string }) {
    // do something
}

// MyArgs is really just a more strongly typed version of {[propertyName: string]: string}
interface MyArgs {
    foo: string;
    bar: string;
}

var someArgs: MyArgs = {
    foo: "foo",
    bar: "bar"
}

DoSomething({ foo: "foo", bar: "bar" }); // works
DoSomething(someArgs); // compile error: Index signature is missing in type 'MyArgs'

This doesn't work because someArgs can not be cast to the parameter type used for the function's argument.

This is different from Typescript: Index signature is missing in type because of the readonly modifier which means that the DoSomething function cannot add new propertly to args. This means that an instance of MyArgs will still comply with this interface signature after DoSomething has been invoked against it.

How can I represent this in Typescript? Is there another way of doing this that I am missing?

Upvotes: 2

Views: 2876

Answers (1)

Matt McCutchen
Matt McCutchen

Reputation: 30879

An object literal type is assignable to a type with an index signature if the property types are compatible, but an interface type is not; see this comment. Once you annotate someArgs as type MyArgs, the information that it was an object literal is lost and only the MyArgs type is used for checking assignability to the parameter type of DoSomething. The readonly modifier is irrelevant: the question is whether someArgs satisfies TypeScript's (very imperfect) heuristic for being unlikely to have had non-string properties added before it is passed to DoSomething.

To make the example work, you can just change MyArgs to an object literal type:

type MyArgs = {
    foo: string;
    bar: string;
};

Upvotes: 5

Related Questions