Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/loops/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Typescript 类型脚本循环类型化对象_Typescript_Loops_Types_Typescript Typings - Fatal编程技术网

Typescript 类型脚本循环类型化对象

Typescript 类型脚本循环类型化对象,typescript,loops,types,typescript-typings,Typescript,Loops,Types,Typescript Typings,我有这个验证文件 interface Rule { required?: true; isNumber?: true; isDate?: { format: string; } // ... some other rules // ruleNames: RuleOptions } const RuleMap: { [key in keyof Required<Rule>]: ( value: any, options: Required&

我有这个验证文件

interface Rule {
  required?: true;
  isNumber?: true;
  isDate?: {
    format: string;
  }
// ... some other rules
// ruleNames: RuleOptions
}

const RuleMap: {
  [key in keyof Required<Rule>]: (
    value: any,
    options: Required<Rule>[key]
  ) => boolean;
} = {
  required: (value) => value != null,
  isNumber: (value) => isNumber(value),
  isDate: (value, options) => isDate(value, options),
//...otherRules
}

// now I have a fairly strong typed object RuleMap
RuleMap.isDate('foo', { format: "DD/MM/YYYY" }); // no problem
RuleMap.required('foo', { format: "DD/MM/YYYY" }); // throws error
e、 g: 指定
isDate
时,
RuleMap
强制我为函数输入确切的
isDate
选项

当循环执行
规则
时,我希望typescript知道我正在将确切的
规则名
的规则选项传递给函数


可能吗?如果是这样的话,我应该怎么做?

问题恰恰在于说明
myRules
Rule
,这意味着TS在编译时不知道该对象中有哪些字段,它将其视为
Rule
,因此字段可以存在,也可以不存在

您的循环是通过
Rule
而不是
typeofmyrules
中的所有键来输入的,实际上它们的一部分不在那里,但是type system没有看到这一点。在值级别,很明显,您要通过
myRules
,如果您这样做,字段就在那里,但是对于类型级别
myRules
,它只是
Rule
,并且具有可以不定义值的键。这与以下简化示例中发生的情况完全相同:

const ruleName: "required" | "isNumber" | "isDate" = 'isDate';
const value = myRules[ruleName]; // value can be undefined!
以上就是在
forEach
中发生的事情,键被键入为
规则的键,值可以是
未定义的
与被调用函数的要求冲突的,要求被声明为-
选项:必需的[key]
,因此它不允许
未定义的
。这是一个错误

好的,那么我们能做些什么呢?简单的解决方案是只使用
const
直接类型的
myRules

const myRules = {
  isNumber: true
} as const; // pay attention here

(Object.keys(myRules) as (keyof typeof myRules)[]).forEach((ruleName) => {
  const value = 1; // example
  RuleMap[ruleName](value, myRules[ruleName]);
});
由于
ruleName
始终在类型中,因此
myRules[ruleName]
永远不会未定义,因此可以正常工作
const
允许type system使用与运行时相同形状的对象


我想你需要在更真实的环境中使用它。在这种情况下,我们需要有通用的,这将允许as使用精确的
规则
接口的狭窄类型。考虑下面的例子:

type OnlyKeysInRule<T extends Rule> = {
  [K in keyof Rule]: T[K]
} & {
  [K in Exclude<keyof T, keyof Rule>]: never
}
function doStaff<R extends Rule>(rules: OnlyKeysInRule<R>) {
  (Object.keys(rules) as (keyof OnlyKeysInRule<R> & keyof typeof RuleMap)[]).forEach((ruleName) => {
    const value = 1; // example
    RuleMap[ruleName](value,  rules[ruleName]);
  });
}
doStaff(myRules) // is ok
doStaff({isNumber: true, isHelicopter: false}) // error as expected - `isHelicopter` is not define in RuleMap
type OnlyKeysInRule={
[K in keyof规则]:T[K]
} & {
[K in Exclude]:从不
}
函数doStaff(规则:OnlyKeysInRule){
(Object.keys(rules)as(keyof OnlyKeysInRule和keyof typeof RuleMap)[])。forEach((ruleName)=>{
const value=1;//示例
RuleMap[ruleName](值,规则[ruleName]);
});
}
doStaff(myRules)//可以吗
doStaff({isNumber:true,ishlicopter:false})//预期错误-`ishlicopter`未在规则映射中定义
说明:

  • OnlyKeysInRule
    是唯一的映射,表示-您可以传递在
    规则中只有字段的对象。为什么它很重要-因为
    R扩展规则
    意味着类型R可以有附加字段,这意味着
    RuleMap[ruleName]
    操作不安全,因为
    ruleName
    可以是
    RuleMap
    中不存在的附加字段,所以此类型可以防止此类操作
  • as(keyof OnlyKeysInRule&keyof typeof RuleMap)
    我们说我们只通过
    RuleMap
    R
    中的键进行循环。在这里,TS无法推断
    OnlyKeysInRule
    已经足以防止这种情况,这就是为什么需要使用union

这里的问题是typescript正在工作,它抛出了一个错误编译,因为如果不检查类型,就不能在同一个循环中为不同的规则应用相同的参数。如何让typescript知道我正在传递正确的规则?事实上,我通过了你想要的正确规则。谢谢!我真的需要那个真实环境的例子!
type OnlyKeysInRule<T extends Rule> = {
  [K in keyof Rule]: T[K]
} & {
  [K in Exclude<keyof T, keyof Rule>]: never
}
function doStaff<R extends Rule>(rules: OnlyKeysInRule<R>) {
  (Object.keys(rules) as (keyof OnlyKeysInRule<R> & keyof typeof RuleMap)[]).forEach((ruleName) => {
    const value = 1; // example
    RuleMap[ruleName](value,  rules[ruleName]);
  });
}
doStaff(myRules) // is ok
doStaff({isNumber: true, isHelicopter: false}) // error as expected - `isHelicopter` is not define in RuleMap