TypeScript - 仅提取接口成员 - 可能吗?

时间:2018-06-13 14:21:03

标签: typescript

有没有办法从属于某个接口的对象中动态提取成员(即不再显式指定它们),如下所示:

let subset = { ...someObject as ISpecific }; 

目前我得到someObject碰巧拥有的所有成员。 所以扩散运营商在这里不起作用。有没有办法做到这一点?

示例:

interface ISpecific { A: string; B: string; }
class Extended implements ISpecific { public A: string = '1'; public B: string = '2'; public C: string = '3'; }

let someObject = new Extended(); 
let subset = { ...someObject as ISpecific }; 
console.log(subset);  // -> { A, B, C } but want { A, B }

TypeScript强制转换只是编译器的提示,而不是运行时的实际转换。

5 个答案:

答案 0 :(得分:8)

由于打字稿接口在运行时不存在,我们无法使用它们来指导任何运行时行为,只需编译时类型检查。但是,我们可以创建一个与接口具有相同属性的对象(例如,具有类型true的所有属性以简化初始化),并且如果此对象具有任何更多或更少的字段,则使编译器触发错误。接口。我们可以使用此对象作为我们提取的属性的指南:

function extract<T>(properties: Record<keyof T, true>){
    return function<TActual extends T>(value: TActual){
        let result = {} as T;
        for (const property of Object.keys(properties) as Array<keyof T>) {
            result[property] = value[property];
        }
        return result;
    }
}

interface ISpecific { A: string; B: string; }
const extractISpecific = extract<ISpecific>({ 
    // This object literal is guaranteed by the compiler to have no more and no less properties then ISpecific
    A: true,
    B: true
})
class Extended implements ISpecific { public A: string = '1'; public B: string = '2'; public C: string = '3'; }

let someObject = new Extended(); 
let subset = extractISpecific(someObject); 

答案 1 :(得分:1)

如果您想限制使用的类型,您可以通过以下方式安全地完成:

let subset = someObject as ISpecific; 

属性仍然存在于subset上,但编译器将阻止您依赖它们,即subset.age将在下面失败,尽管属性 仍然存在。

interface ISpecific {
    name: string;
}

const someObject = {
    name: 'Fenton',
    age: 21
};

let subset = someObject as ISpecific; 

console.log(subset.age);

你可以通过这样的解构来真的抛弃属性,危险的是你需要在...subset之前的列表中包含“我不想要的所有东西”。 / p>

interface ISpecific {
    name: string;
}

const someObject = {
    name: 'Fenton',
    age: 21
};

let { age, ...subset } = someObject;   

console.log(JSON.stringify(someObject));
console.log(JSON.stringify(subset));

答案 2 :(得分:0)

可以使用装饰器来实现(参见最后的要求)。 它只能与方法一起使用(复制属性get / set accessor只产生其瞬时返回值,而不是访问器函数)。

File ID: 1kIDop9cX5CvL5jxxxxxxxxxxxxyP

(这需要在tsconfig.json和ES5目标中使用compilerOption&#34; experimentalDecorators&#34;:true,http://www.typescriptlang.org/docs/handbook/decorators.html处有更多信息)

答案 3 :(得分:0)

不幸的是,您不需要指定并重复这些部分。

export interface Machine {
  id: string;
  name: string;
  logo: string;
  location: Location;
  products: Item[];
  restriction: string;
  categories: string[];
  star: number;
  distance: number;
}

export interface MachineIdentification {
  id: string;
  name: string;
  logo: string;
  location: Location;
}

//Object Destructuring fat object in parts
const {id, name, logo, location} = machine; 

//Compose a ligth object from parts and apply interface type
const mi: MachineIdentification = {id, name, logo, location}; 

答案 4 :(得分:-1)

更新:这似乎不起作用,所以不是答案。

owner = permissionsList.Permissions.FirstOrDefault(f => f.Role.ToLowerInvariant() == "owner")?.DisplayName;

Object.create使用指定的原型创建一个新对象,但TypeScript强制转换仅仅是编译器的提示。它可能使用具体的类层次结构,然后引用原型,但这可能包括比接口声明更多的实际成员。