Reputation: 1859
I am building a utility method that returns the extended type.
Somehow, my approach to building a method has the following compile error.
Type '{ name: string; }' is not assignable to type 'A'. '{ name: string; }' is assignable to the constraint of type 'A', but 'A' could be instantiated with a different subtype of constraint 'Base'.
type Base = {
name: string;
}
type Ex1 = Base & {other: string};
type Ex2 = Base & {another: string};
type OtherType = {
name: string
}
const convert = <A extends Base>(other: OtherType): A => {
const ret = {
name: other.name
};
return ret;
}
const otherType = {name: 'hello'};
const ex1 = convert<Ex1>(otherType);
ex1.other = 'other Value';
const ex2 = convert<Ex2>(otherType);
ex2.another = 'another Value';
see playground
Upvotes: 1
Views: 150
Reputation: 3604
With cast, you can do anything. However, what you want to achieve is the same as:
type Base = {
name: string;
}
type Ex1 = Base & {other: string};
type Ex2 = Base & {another: string};
type OtherType = {
name2: string
}
const convertToBase = (other: OtherType): Base => ({
name: other.name2
});
const otherType = {name2: 'hello'};
const ex1 = convertToBase(otherType) as Ex1;
ex1.other = 'other Value';
const ex2 = convertToBase(otherType) as Ex2;
ex2.another = 'another Value';
With that, at least, you are telling the truth, your method converts OtherType
to Base
, and not to Ex1
or Ex2
. By using cast, you can assign a new property to the object, but you lost the interest of using typescript for type check: If you forgot to assign ex1.other = 'other Value';
, your ex1
will still be recongnized as Ex1
by typescript but it's not the truth:
const ex1 = convertToBase(otherType) as Ex1;
// ex1.other = 'other Value'; // forgot to do this
console.log(ex1.other.toUpperCase()); // Got runtime error here
It would be better to do it with destructuring assignment:
const ex1: Ex1 = {
...convertToBase(otherType),
other: 'other Value',
};
const ex2: Ex2 = {
...convertToBase(otherType),
another: 'another Value',
};
const ex3: Ex1 = {
...convertToBase(otherType),
another: 'another Value', // Error here
};
Upvotes: 1
Reputation: 9903
You have to add Base
for your return type too. Like this:
const f = <A extends Base>(a: string): A | Base => {
const ret = {
name: a
};
return ret;
}
See Playground
You edit your question so I have to edit my answer!
Edit
You can use ret as A;
in your convert
function. Like this:
const convert = <A extends Base>(other: OtherType): A => {
const ret = {
name: other.name
};
return ret as A;
}
See Working sample
Upvotes: 1