Reputation: 10318
I have an interface Base
, which interfaces A
and B
extend, and A
and B
both have properties that are unique and don't exist in the other. In my code, I have some data that will change depending on the type:
interface Base {
basicProperty: any,
basicProperty2: any
}
interface A extends Base {
aSpecificProperty: any
}
interface B extends Base {
bSpecificProperty: any
}
function(type): A | B {
const data: A | B = {
basicProperty: 1,
basicProperty2: 2
}
if (type === 'A') {
// Data should be type A
data.aSpecificProperty = 3;
} else if (type === 'B') {
// Data should be type B
data.bSpecificProperty = 3;
}
return data;
}
Is there any way to accomplish this without TypeScript complaining about the type not containing the right properties? Or, is there a way to reassign/specify the type of data
from A | B
to A
or B
?
Upvotes: 1
Views: 1877
Reputation: 12414
There are many ways to achieve what you want. If your return is based on type: string
argument, why not use something like:
interface Base { }
class A implements Base { name: string }
class B implements Base { value: number }
function fn(type): Base {
if (type == 'A') {
const data: A = {
name: 'abc'
}
//...
return data;
}
if (type == 'B') {
const data: B = {
value: 10
}
//...
return data;
}
}
I need more information about your problem to give a better answer, but, since you have a Base
class as you said, something like this could help you.
UPDATE
Based on your updates and comments I'll suggest the following code:
interface Base {
basicProperty: any,
basicProperty2: any
}
interface A extends Base {
aSpecificProperty: any
}
interface B extends Base {
bSpecificProperty: any
}
function typeFactory<T extends Base>(obj: Base, ext: Partial<T>) {
return Object.assign(obj, ext) as T;
}
function myFn(type): A | B {
const data: Base = {
basicProperty: 1,
basicProperty2: 2
}
switch (type) {
case 'A':
return typeFactory<A>(data, {
aSpecificProperty: 3
});
case 'B':
return typeFactory<B>(data, {
bSpecificProperty: 3
});
}
// ...
}
reference about
Object.assign(...)
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
Upvotes: 1
Reputation: 784
Have you considered using the typeof operator?
interface IBase {
name: string;
sayName();
}
class A implements IBase {
constructor(public name: string) { }
sayName() {
console.log(name);
}
onlyA()
{
console.log("I exist only in A");
}
}
class B implements IBase {
constructor(public name: string) { }
sayName() {
console.log(name);
}
onlyB()
{
console.log("I exist only in B");
}
}
function myFunc<T extends IBase>(arg: T ) : any {
const data: T = arg;
if (typeof(data) === typeof(A)) {
// Data should be type A
data.sayName();
let aObj: A = data as any;
aObj.onlyA();
} else if (typeof(data) === typeof(B)) {
// Data should be type B
data.sayName();
let bObj: B = data as any;
bObj.onlyB();
}
return data;
}
let a = myFunc(new A("I am A"));
let b = myFunc(new B("I am B"));
a.onlyA();
b.onlyB();
This essentially let the generic function check the type and return an object of type any.
Is this what you were looking for or i did not follow the question right?
Per your example it would look something like
interface IBase{
}
class A implements IBase {
}
class B implements IBase{
}
function myFunc<T extends IBase>(type: T ): A | B {
const data: A | B = {
}
if (typeof(type) === typeof(A)) {
// Data should be type A
} else if (typeof(type) === typeof(B)) {
// Data should be type B
}
return data;
}
Upvotes: 1