Reputation: 1590
I want to create a function f
that takes a string, and creates an object, where key
is the only field set.
I also want the function to typecheck the interface A
to make sure that the key
-field is the only required field on the object. (There will be other optional fields).
Problem:
Is it possible to express the type A
so that function f
is valid – and doesn't produce a type error – and still typechecks A
correctly when used?
export function f<A extends { key: string }>(key: string): A {
return { key }; // This produces compile error TS2322: (see below)
}
// This be a few different interfaces, but they all have in common that
// the key-field is the only required field.
interface WithKey {
key: string;
ignoreMe?: string;
}
const result = f<WithKey>('myKey');
Compiler error:
TS2322: Type '{ key: string; }' is not assignable to type 'A'. '{ key: string; }' is assignable to the constraint of type 'A', but 'A' could be instantiated with a different subtype of constraint '{ key: string; }'.
Upvotes: 4
Views: 2357
Reputation: 13539
The problem is that your statement says that it accepts a type that has to have key
of string
and this type will be returned.
it means if I pass there
{key: 1, requiredField: 5}
it returns the same type where I have requiredField
.
But the implementation return { key }
breaks this statement, because it doesn't return requiredField
anymore. This causes TS2322.
A possible solution - simply say interface you return.
export function f(key: string): { key: string } { // <- return type
return { key };
}
interface WithKey {
key: string;
ignoreMe?: string;
}
const result: WithKey = f('myKey');
result.key; // works
result.ignoreMe // works (undefined)
Upvotes: 3