Typescript:将对象扩展到类型化对象中包含不属于类型的键

k4emjkb1  于 2022-12-05  发布在  TypeScript
关注(0)|答案(2)|浏览(142)

我有两个具有未知键的对象,我想合并到一个具有类型的新对象中,所有不属于该类型的键都应该省略。
举一个实际的例子:我有要合并的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,它们不是类型的一部分
我如何才能做到这一点?

zxlwwiss

zxlwwiss1#

就像@ghybs的注解一样,typescript类型在运行时不存在(仅在编译时),所以你不能使用类型信息来过滤实际数据。这是因为你实际上并没有运行“typescript”代码。Typescript被编译到Javascript中,这就完全剥离了类型,就好像它们一开始就不存在一样。
但是,还有其他方法可以获取运行时类型数据。这些方法要复杂得多,通常在使用typescript构建大规模系统时更有用:
1.使用架构验证库(如Zod:https://github.com/colinhacks/zod。这允许您定义一个“模式”(您希望运行时代码能够读取的内容),同时生成一个类型脚本定义。
1.使用Reflect Metadata,它在装饰器和类的基础上做了很多神奇的事情。NestJS有一个很好的例子来说明如何做到这一点:是的。

eqoofvh9

eqoofvh92#

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))

希望能有所帮助

相关问题