Reputation: 157
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
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