Typescript: Spreading Objects into a typed Object包含了不属于该类型的键



我有两个键未知的对象,我想合并成一个具有类型的新对象,所有不属于该类型的键都应该省略。

举一个实际的例子:我有URL查询参数(由用户公开和可编辑)和cookie值,我想合并。我想省略所有不需要的参数,只保留我允许/需要的参数(由类型定义)

type RequestAdditionalParameters = {
session?: string | null;
searchInput?: string | null;
id?: string | null;
}
//I use a generic because RequestAdditionalParameters actually has multiple possible
//types, but I think that shouldn't matter
export const mergeParameters = <T extends RequestAdditionalParameters>(
cookies: Record<string, string | null>,
queryParams: Record<string, string | null>
): T => {
const allowedParams: T = { ...cookies, ...queryParams };
return allowedParams;
};
const additionalParameters = mergeParameters<SearchParameters>(
{ session, id },
{ searchInput, anotherParam }
);
result = {
session: 'kjn33fbf4fkl3w3ff3f3ffuu',
searchInput: 'stackoverflow',
id: '345644783',
anotherParam: 'should not be here',
}
expectedResult = {
session: 'kjn33fbf4fkl3w3ff3f3ffuu',
searchInput: 'stackoverflow',
id: '345644783',
}

如果我记录输出,我仍然得到不属于

类型的不想要的kesa我怎样才能做到这一点?

就像@ghybs的注释一样,typescript类型在运行时(仅在编译时)不存在,所以你不能使用类型信息来过滤实际数据。这是因为你实际上并没有运行"typescript"代码。Typescript被编译成Javascript, Javascript完全去掉了这些类型,就好像它们一开始就不存在一样。

但是,还有其他方法可以获得运行时类型数据。它们要复杂得多,在使用typescript构建大型系统时通常更有用:
  1. 使用模式验证库,如Zod: https://github.com/colinhacks/zod。这让你可以定义一个模式。(你希望你的运行时代码能够读取),同时生成一个typescript定义。
  2. 使用反射元数据,它在底层对装饰器和类做了很多神奇的事情。NestJS有一个很好的例子来说明这是如何完成的:https://docs.nestjs.com/techniques/validation.

Kevin Bai和Kruben是对的,你不能在编译时这样做。

没有添加zod或yup或其他类似的东西你可以这样做,如果它可以匹配。

这不是很干净,它可以与您的代码片段一起工作,但可能不适用于您的实际代码…

const requestAdditionalParametersKeys = ["session", "searchInput", "id"] as const;
type RequestAdditionalParametersKeys = typeof requestAdditionalParametersKeys[number];
type RequestAdditionalParameters = { [key in RequestAdditionalParametersKeys]?: string | null };
// inherits is done  like this : 
const searchParametersKeys = [...requestAdditionalParametersKeys, "search"] as const;
type SearchParametersKeys = typeof searchParametersKeys[number];
type SearchParameters = { [key in SearchParametersKeys]?: string | null };

const mergeParameters = <T extends RequestAdditionalParameters, K extends keyof T>(
allAllowedKeysOfT: Array<string>,
cookies: Record<string, string | null>,
queryParams: Record<string, string | null>
): T => {
const allowedParamsCandidate = { ...cookies, ...queryParams };
const result:  { [key in keyof T]?: string | null } = {}; 
for (const key in allowedParamsCandidate) {
if (allowedParamsCandidate[key] != null)
if (allAllowedKeysOfT.includes(key)) {
result[key as K] = allowedParamsCandidate[key];
}
}
return result as T;
};
const additionalParameters = mergeParameters<SearchParameters, keyof SearchParameters>(
searchParametersKeys as unknown as string[],
{ session: 'kjn33fbf4fkl3w3ff3f3ffuu', id: '345644783' },
{ searchInput: 'stackoverflow', anotherParam: 'should not be here' }
);
console.log(JSON.stringify(additionalParameters, null, 2))

希望能有所帮助

相关内容

最新更新