Make overProp<Obj>一个参数的函数接口 [英] Make overProp&lt;Obj&gt; function interface with one param

查看:17
本文介绍了Make overProp<Obj>一个参数的函数接口的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想创建一个函数 overProp ,它的工作方式如下:

I want to make a function overProp that would work the following way:

type Obj = {a: string, b: number}

const overA = overProp<Obj>('a', (a) => a + 'b') // takes only one type param, type of object over which it will perform

const obj = {a: 'str', b: 1}

const obj2 = overA(obj) // this would set `obj.a` to `ab`

所以 overProp 函数应该将第一个参数限制为 Obj 的键,第二个参数 over 方法应该采用 Obj[P],其中 P 是提供了第一个道具.

So overProp function should limit first param to be key of Obj, second param over method should take Obj[P] where P is supplied the first prop.

到目前为止我唯一能做到的,所以我需要将 a 复制为类型参数和函数参数:

The only thing I could achieve so far, so I need to duplicate a as type param and as function param:

const overA = overProp<Obj, 'a'>('a', (a) => a + 'b') 

使用此实现:

const overProp = <T, P extends keyof T>(p: P, over: (val: T[P]) => T[P]) => {
  return (obj: T) => ({
    [p]: over(obj[p]),
    ...obj
  })
}

所以这就是我认为它应该工作的方式:

So this is the way I thought it should work:

overProp<Obj>('a', (a) => a) // no error

overProp<Obj>('a', (a) => 'a') // no error

overProp<Obj>('b', (b) => 1) // no error

overProp<Obj>('c', ...) // error, not key 'c' in Obj

overProp<Obj>('a', (a) => 1) // error, type of key `a` is `string`

我想知道是否可以使用最新的 TS 版本 (3.5).

I wonder if it is possible with the latest TS version (3.5).

推荐答案

TypeScript 目前不支持 部分类型参数推断;如果一个类型有两个类型参数,则必须同时指定它们,否则编译器将同时推断它们.(嗯,有 类型参数默认值 但这也不算作推理).

TypeScript doesn't currently support partial type parameter inference; if a type has two type parameters, you either have to specify both of them or the compiler will infer both of them. (Well, there are type parameter defaults but that doesn't count as inference either).

我知道有两种解决方法.第一个是 currying,在这里,您拥有多个类型参数的单一泛型函数,而不是返回另一个泛型函数的泛型函数.在其中一个指定类型参数,另一个让编译器推断它:

There are two workarounds I know of for this. The first is currying, where instead of having a single generic function of multiple type parameters, you have a generic function which returns another generic function. On one of them you specify the type parameter, and the other you let the compiler infer it:

const overPropCurried = <T>() => <P extends keyof T>(
  p: P,
  over: (val: T[P]) => T[P]
) => {
  return (obj: T) => ({
    [p]: over(obj[p]),
    ...obj
  });
};

const overPropObj = overPropCurried<Obj>();
overPropObj("a", a => a); // no error
overPropObj("a", a => "a"); // no error
overPropObj("b", b => 1); // no error
overPropObj("c", c => 2); // error, not key 'c' in Obj
overPropObj("a", a => 1); // error, type of key `a` is `string`

另一种解决方法是使用单个函数,该函数采用与您要指定的类型相对应的虚拟参数.您作为虚拟参数传递的实际值并不重要,因为函数实现忽略了它……事实上,只要编译器认为该值是正确的类型,它甚至都不会在运行时必须是一个:

The other workaround is to use a single function which takes a dummy parameter corresponding to the type you'd like to specify. The actual value you pass as the dummy parameter doesn't matter because the function implementation ignores it... in fact, as long as the compiler thinks the value is of the right type it doesn't even have to be one at runtime:

const overPropDummy = <T, P extends keyof T>(
  dummy: T, // ignored
  p: P,
  over: (val: T[P]) => T[P]
) => {
  return (obj: T) => ({
    [p]: over(obj[p]),
    ...obj
  });
};

const dummyObj = null! as Obj; // not really an Obj but it doesn't need to be

overPropDummy(dummyObj, "a", a => a); // no error
overPropDummy(dummyObj, "a", a => "a"); // no error
overPropDummy(dummyObj, "b", b => 1); // no error
overPropDummy(dummyObj, "c", c => 2); // error, not key 'c' in Obj
overPropDummy(dummyObj, "a", a => 1); // error, type of key `a` is `string`

无论哪种方式都有效,而且都不是完美的.我倾向于自己使用柯里化,特别是如果我可以多次使用部分结果(就像我在上面使用 overPropObj 所做的那样).无论如何,希望有所帮助;祝你好运!

Either way works, and neither way is perfect. I tend to use currying myself, especially if I can use the partial result multiple times (as I've done above with overPropObj). Anyway, hope that helps; good luck!

代码链接

这篇关于Make overProp<Obj>一个参数的函数接口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆