英文:
Partial application of TypeScript object
问题
我想要部分应用一个对象到一个接受单个对象作为参数的函数中。我已经能够使下面的`partial`函数返回一个表现如预期的函数,但我不能让partial函数拒绝提供的`x`对象中多余的键:
```typescript
/******
* Things that I couldn't make work.
*/
type Impossible<K extends keyof any> = {
[P in K]: never;
};
type NoExtraProperties<T, U extends T = T> = U & Impossible<Exclude<keyof U, keyof T>>;
type Exactly<T, X> = T & Record<Exclude<keyof X, keyof T>, never>;
/*********
* Attempted implementation
*/
const partial = <T, X extends Partial<T> = Partial<T>>(fn: (arg: T) => unknown, x: X): ((arg: Omit<T, keyof X>) => ReturnType<typeof fn>) => {
return (arg) => fn(Object.assign(x, arg) as T);
}
// Example function to partially apply
const fn = ({name, age, alive}: {name: string, age: number, alive: boolean}): string => {
return name + age.toString()
}
// plain function call
const fullCallResult = fn({
name: "Maono",
//sadfadsfdas: "sdfadsfa", // Error here, as expected.
age: 19,
alive: true
});
const partialllyApplied = partial(fn, {
name: "asdfasdf",
sadfadsfdas: "sdfadsfa" // <- No error here. I want this to give an error.
//, age: 32
//, alive: true
});
const partialllyAppliedResult = partialllyApplied({agde: 44, alive: false}) // <-- Error here, good, there is a type.
const partialllyAppliedResult2 = partialllyApplied({age: 44, alive: false})
如何使partial
函数限制从传递的x
对象中接受哪些键,模仿直接函数调用?
<details>
<summary>英文:</summary>
I want to partially apply an object to a function that accepts a single object as argument. I have been able to make the `partial` function below return a function that behaves as expected, but I am not able to make the partial function reject extra keys for the provided `x`:
```typescript
/******
* Things that I couldn't make work.
*/
type Impossible<K extends keyof any> = {
[P in K]: never;
};
type NoExtraProperties<T, U extends T = T> = U & Impossible<Exclude<keyof U, keyof T>>;
type Exactly<T, X> = T & Record<Exclude<keyof X, keyof T>, never>
/*********
* Attempted implementation
*/
const partial = <T, X extends Partial<T> = Partial<T>>(fn: (arg: T) => unknown, x: X): ((arg: Omit<T, keyof X>) => ReturnType<typeof fn>) => {
return (arg) => fn(Object.assign(x, arg) as T);
}
// Example function to partially apply
const fn = ({name, age, alive}: {name: string, age: number, alive: boolean}): string => {
return name + age.toString()
}
// plain function call
const fullCallResult = fn({
name: "Maono",
//sadfadsfdas: "sdfadsfa", // Error here, as expected.
age: 19,
alive: true
});
const partialllyApplied = partial(fn, {
name: "asdfasdf",
sadfadsfdas: "sdfadsfa" // <- No error here. I want this to give an error.
//, age: 32
//, alive: true
});
const partialllyAppliedResult = partialllyApplied({agde: 44, alive: false}) // <-- Error here, good, there is a type.
const partialllyAppliedResult2 = partialllyApplied({age: 44, alive: false})
How could you make the partial
function restrict what keys are accepted from the passed x
object mimicking a direct function call?
答案1
得分: 2
function partialApply<T, R, X extends Partial<T>>(
fn: (arg: T) => R,
def: X & { [K in keyof X]-?: K extends keyof T ? T[K] : never }
): (rest: { [K in keyof (Omit<T, keyof X> & Partial<T>)]: T[K] }) => R {
return function apply(rest) {
return fn({ ...def, ...rest })
}
}
const fn = ({ name, age, alive }: { name: string, age: number, alive: boolean }): string => {
return name + age.toString();
}
const apply1 = partialApply(fn, { age: 123 })
partialApply(fn, { age: 123 as 123 | undefined })
partialApply(fn, { age: 123 })({ alive: true })
英文:
function partialApply<T, R, X extends Partial<T>>(
fn: (arg: T) => R,
// X, but keyof T is not optional and unwanteds are never
def: X & { [K in keyof X]-?: K extends keyof T ? T[K] : never }
// T, but keyof X is optional
): (rest: { [K in keyof (Omit<T, keyof X> & Partial<T>)]: T[K] }) => R {
return function apply(rest) {
// create new object, rest may override def
return fn({ ...def, ...rest })
}
}
// Example function to partially apply
const fn = ({ name, age, alive }: { name: string, age: number, alive: boolean }): string => {
return name + age.toString();
}
const apply1 = partialApply(fn, { age: 123 })
// ^?
// const apply1: (rest: {
// name: string;
// alive: boolean;
// age?: number | undefined;
// }) => string
partialApply(fn, { age: 123 as 123 | undefined })
// ~~~ Type '123 | undefined' is not assignable to type '123'.
partialApply(fn, { age: 123 })({ alive: true })
// ~~~~~~~~~~~~~~~ Property 'name' is missing in type '{ alive: true; }'
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论