将对象转换为类型

时间:2016-12-25 03:49:15

标签: javascript typescript

我有一个类型

export type LocationQuery = {
    showWarnings: boolean;
    showErrors: boolean;
    startDate: string;
    endDate: string;
    quickDate: number;
}

现在,我想从location.query模块转换history以转换为此类型。

这种不方便的方法是手动:

let query: LocationQuery;
query.showWarnings = location.query['showWarnings'];
query.showErrors = location.query['showErrors'];
...

但是有更方便的单线方式吗?请注意location.query可能包含其他我不关心的字段(如果有location.query['someOtherField'],则不应进入query

2 个答案:

答案 0 :(得分:0)

有太多方法可以做到这一点 这可能是其中之一

import * as assert from "assert";

/**
 * will copy all blueprint.keys from source 
 * or default to blueprint (default) value;
 * @returns a copy of blueprint with source values
 */
const copy = <TSource extends {}, TTarget extends {}>
  (source: TSource, bluePrint: TTarget): TTarget => {
    let result: any = {};
    // see: Object.getOwnPropertyNames, its shallow 
    for (let key of Object.getOwnPropertyNames(bluePrint)) {
        result[key] = source.hasOwnProperty(key)
            ? source[key]
            // default to blueprint prop, will be undefined 
            // but they key will exists
            : bluePrint[key];
    }
    return result;
}

export type LocationQuery = {
    showWarnings: boolean;
    showErrors: boolean;
    startDate: string;
    endDate: string;
    quickDate: number;
}

interface History {
    showWarnings: boolean;
    showErrors: boolean;
    startDate: string;
    endDate: string;
    quickDate: number;
    somethingElse: any;
}

/**
 * Default Value, blueprint, skeleton, shape,etc 
 */
const empty: LocationQuery = {
    showWarnings: undefined,
    showErrors: undefined,
    startDate: undefined,
    endDate: undefined,
    quickDate: undefined,
};

/**
 * test's source subject
 */
const history: History = {
    showWarnings: false,
    showErrors: false,
    startDate: '2016-12-01',
    endDate: '2016-12-31',
    quickDate: 1,
    somethingElse: false
}

/**
 * LocationQuery it's 'Partial'History
 */
const expected: LocationQuery = {
    showWarnings: false,
    showErrors: false,
    startDate: '2016-12-01',
    endDate: '2016-12-31',
    quickDate: 1,
}


describe("copy", () => {

    it("shallow copy, all desired members", () => {
        let result = copy(history, empty);
        assert.deepEqual(expected, result);
         // All Key Present?
         // somethingElse shoudl be missing...
        assert.equal(
            "showWarnings, showErrors, startDate, endDate, quickDate",
        Object.keys(result).reduce( (a,b)=> a+ ", "+b));
    });

    it("shallow copy, all desired members and defaults to missing props", () => {

        // doesn't provide all memebers
        const historyLike = {
            showWarnings: true,
            showErrors: true,
        }

        let result = copy(historyLike, empty);

        const expected_result_with_defaults = {
            showWarnings: true,
            showErrors: true,
            startDate: undefined,
            endDate: undefined,
            quickDate: undefined,
        };

        // Values Ok? 
        assert.deepEqual(expected_result_with_defaults, result);

        // All Key Present?
        assert.equal(
            "showWarnings, showErrors, startDate, endDate, quickDate",
            Object.keys(result).reduce( (a,b)=> a+ ", "+b)
        )
    });
})

Typescript 2.1 +

的另一个
/**
 * Requires Typescript 2.1 up
 * copy specified key from derived type
 * where TSource is superset of TResult 
 */
const copy = <TSource extends TResult, TResult extends {}>(source: {}, ...keys: (keyof TResult)[]): TResult => {    
    let result: any = {};
    for(let key of keys){        
        result[key] = source.hasOwnProperty(key) ? (<any>source)[key] : null;
    }
    return result
}


describe("copy", () => {   
    it("copy specified members ", () => {
        let result = copy<History, LocationQuery>(
         /*from*/ history,
         "showWarnings" ,
         "showErrors",
         "startDate",
         "endDate", 
         "quickDate");
        assert.deepEqual(expected, result);
        assert.equal(
            "showWarnings, showErrors, startDate, endDate, quickDate",
            Object.keys(result).reduce( (a,b)=> a+ ", "+b)
        )        
    });
})

答案 1 :(得分:0)

使用字段名称列表:

function toLocationQuery(source) {
    const fields = ['showWarnings', 'showErrors', 'startDate', 'endDate', 'quickDate']
    let res = {}
    for (let k of fields) {
        if (source[k] === undefined)
            throw new Error(`Missing field "${k}"`)
        res[k] = source[k]
    }
    return res as LocationQuery
}

let query = toLocationQuery(location.query)

或相同的代码但不重新声明每个调用的字段列表:

const toLocationQuery = (function () {
    const fields = ['showWarnings', 'showErrors', 'startDate', 'endDate', 'quickDate']
    return function (source) {
        let res = {}
        for (let k of fields) {
            if (source[k] === undefined)
                throw new Error(`Missing field "${k}"`)
            res[k] = source[k]
        }
        return res as LocationQuery
    }
})()

let query = toLocationQuery(location.query)