You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript仅允许无!后缀键追加!的模板字面量类型约束方案

TypeScript 嵌套pick方法重复追加!后缀的类型约束问题

我之前尝试实现一个Schema类,既支持直接传入属性键作为参数,也支持传入属性键追加!后缀的形式,用来标记对应字段为必填项。

最终实现的类核心结构如下:

export class Schema<PropType extends Record<string, any>> {
  properties: Partial<PropType> = {};

  constructor(properties: PropType) {
    this.properties = properties;
  }

  /**
   * 从已选中的字段范围内挑选指定字段
   */
  pick = <K extends keyof PropType | `${Extract<keyof PropType, string>}!`>(
    ...fields: Array<K>
  ) => {
    const newProperties = {} as Record<keyof PropType, unknown>;
    fields.forEach((field) => {
      const { name, required } = this._parse(field);
      newProperties[name] = {
        ...(this.properties[name]),
        required,
      };
    });

    return new Schema<Record<K, unknown>>(
      newProperties
    );
  };

    /**
   * 解析字段字符串,返回原始字段名,以及字段是否必填(以!结尾即为必填)
   */
  _parse = (field: keyof PropType | `${Extract<keyof PropType, string>}!`) => {
    return {
      name: (field as string).replace("!", "") as keyof PropType,
      required: (field as string).split("").reverse()[0] === "!",
    };
  };
}

pick方法是核心逻辑:只要keyName是PropType的合法键,就允许同时选取keyName和keyName!,其中!后缀代表该键为必填项。

基础使用没有问题:

const Person = new Schema({ firstName: 'Fyodor', middleName: 'Mikhailovich', lastName: 'Dostoevsky' });
const SubPerson = Person.pick('firstName', 'lastName!');

现存问题

嵌套多层pick调用时,类型系统会允许重复给字段追加感叹号后缀,以下非法传参不会触发类型报错:

SubPerson.pick(
  'firstName', 
  'lastName!', 
  'lastName!!' // 该参数本不应被类型系统接受
)

需求

需要实现对应的类型约束:当且仅当keyof PropType对应的原始键本身不包含!后缀时,才允许使用${Extract<keyof PropType, string>}!形式的模板字面量类型,彻底阻断重复追加!的非法参数。


内容的提问来源于stack exchange,提问作者Sasha

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 15:39:17