Typescript 如何创建一个具有强类型属性的对象,该对象也不允许引用不存在的属性?

Typescript 如何创建一个具有强类型属性的对象,该对象也不允许引用不存在的属性?,typescript,Typescript,标题有点奇怪,但希望我能举例说明 我有一个对象,它包含一组SQL查询(在编译时定义),如下所示: const queries = { getProductById: { params: { id: 'number' }, sql: `select * from product where id = :id` }, getCustomerById: { params: { id: 'number' }, sql

标题有点奇怪,但希望我能举例说明

我有一个对象,它包含一组SQL查询(在编译时定义),如下所示:

const queries = {
    getProductById: {
        params: { id: 'number' },
        sql: `select * from product where id = :id`
    },
    getCustomerById: {
        params: { id: 'number' },
        sql: `select * from customer where id = :id`
    }

    // ... etc ...
};

export { queries };
interface IQuery {
    params?: { [paramName: string]: string };
    sql: string;
}

const getProductQuery: IQuery = {
    params: { id: 'number' },
    sql: `select * from product where id = :id`
};

const queries = {
    getProductQuery
};

// compiler error, because "nonexistentQuery" doesn't exist
db.executeQuery(queries.nonexistentQuery, { id: 12 });
当我需要在另一个文件中使用其中一个查询时,我可以
导入
查询
对象并通过键引用查询,这是由TypeScript编译器进行类型检查的:

// compiles without issues
db.executeQuery(queries.getProductById, { id: 42 });

// compiler error, because "nonexistentQuery" isn't defined
db.executeQuery(queries.nonexistentQuery, { id: 7 });
现在,我希望能够定义一个接口,将类型安全性添加到我的
查询
变量中(在上面的第一个示例中)。首先,我创建了一个带有索引签名的接口:

interface IQueryList {
    [queryName: string]: {
        params?: { [paramName: string]: string };
        sql: string;
    };
}
但是,当我将此类型注释添加到我的
查询
变量时,我在引用特定查询时会丢失类型安全性:

const queries: IQueryList = {
    getProductById: {
        params: { id: 'number' },
        sql: `select * from product where id = :id`
    }
};

// no compiler error, because "queries" has an index signature
db.executeQuery(queries.nonexistentQuery, { id: 12 });
在定义我的查询时,是否有一种方法可以同时兼顾类型安全性和引用未在
querys
对象上定义的查询时的安全性?

我可以通过使用自己的类型注释标记每个查询来实现这一点,如下所示:

const queries = {
    getProductById: {
        params: { id: 'number' },
        sql: `select * from product where id = :id`
    },
    getCustomerById: {
        params: { id: 'number' },
        sql: `select * from customer where id = :id`
    }

    // ... etc ...
};

export { queries };
interface IQuery {
    params?: { [paramName: string]: string };
    sql: string;
}

const getProductQuery: IQuery = {
    params: { id: 'number' },
    sql: `select * from product where id = :id`
};

const queries = {
    getProductQuery
};

// compiler error, because "nonexistentQuery" doesn't exist
db.executeQuery(queries.nonexistentQuery, { id: 12 });

但我更愿意避免这种情况,因为每个查询都需要单独标记。此外,没有任何东西可以防止格式不正确的对象包含在最终的
查询中。

您可以在定义强制约束时使用辅助函数,但在使用查询对象时保持正确检查:

function defineQueries<T extends IQueryList>(q: T) : T {
    return q;
}

const queries =defineQueries({
    getProductById: {
        params: { id: 'number' },
        sql: `select * from product where id = :id`
    }
});

queries.getProductById; //ok
queries.notAQuery // error
函数定义(q:T):T{
返回q;
}
const querys=definequalies({
getProductById:{
参数:{id:'number'},
sql:`select*from product,其中id=:id`
}
});
querys.getProductById//好啊
querys.notAQuery//错误

没有。鸭子就是鸭子,即使它是一只有三条腿的变异鸭子。另一方面,代理可以帮你做到这一点。但是这样使用它没有多大意义。