Typescript 如何键入具有属性并采用泛型参数的函数

Typescript 如何键入具有属性并采用泛型参数的函数,typescript,generics,typescript-generics,Typescript,Generics,Typescript Generics,假设我有一个函数,它有一个属性userId,在userId和它的参数和返回类型之间应该有一些约束。比如: 接口IMyfunc{ (项目:T):T 用户ID:T } 它的实现类似于: 常量func:IMyfunc=a=>a func.userId=1 然而,到目前为止还不错,我的疑问是,我现在只能用number调用func,不能用string或其他东西调用它,因为当我使用IMyfunc接口时,我必须显式绑定它的类型参数 因此,如果我需要func获取字符串参数,我必须声明另一个使用IMyfunc

假设我有一个函数,它有一个属性
userId
,在
userId
和它的参数和返回类型之间应该有一些约束。比如:

接口IMyfunc{
(项目:T):T
用户ID:T
}
它的实现类似于:

常量func:IMyfunc=a=>a func.userId=1 然而,到目前为止还不错,我的疑问是,我现在只能用number调用
func
,不能用string或其他东西调用它,因为当我使用
IMyfunc
接口时,我必须显式绑定它的类型参数

因此,如果我需要
func
获取字符串参数,我必须声明另一个使用
IMyfunc
的函数express,并将
string
类型绑定到它的类型参数,是什么让我认为这里的泛型类型失去了真正的泛型的含义


有什么方法可以键入一个具有属性的函数,并采用真正通用的通用参数吗?

没有任何方法可以通过调用对象上的方法来更改对象的类型(在您的情况下,为字段赋值)。不过,您可以使用以下方法:

function setUserId<T>(userId: T, func: IMyfunc<unknown>): IMyfunc<T> {
  func.userId = userId;
  return <IMyfunc<T>>func;
}
函数setUserId(userId:T,func:IMyfunc):IMyfunc{
func.userId=userId;
返回函数;
}
这个问题讨论的是“真正的”泛型,我认为它是任意的,目前TypeScript不支持它。TypeScript唯一的泛型值是泛型函数


但我认为你真正想要的是“类型状态”或“类型变异”,即值的类型可以根据值的使用方式而改变。我认为其意图是这样的:

func(4);
const n = func.userId; // n inferred as number
func("a");
const s = func.userId; // s inferred as string
func(false);
const b = func.userId; // b inferred as boolean
function func<U>(item: U): Func<U> {
  const f = <T>(item: T) => func(item);
  return Object.assign(f, { userId: item });
}
const f = func(4);
const n = f.userId; // number
console.log(n); // 4
function func<U>(item: U): { userId: U } {
  return { userId: item };
}

const f = func(4);
const n = f.userId; // 4
console.log(n); // 4

const g = func("a");
const s = g.userId; // string
console.log(s); // 1

const h = func(false);
const b = h.userId; // boolean
console.log(b); // false
…其中,
func.userId
的类型根据以前对
func()
的调用而变化

不幸的是,虽然TypeScript可以通过以下方式缩小某些值的类型(因此类型
string | number
的值可以缩小为类型
string
的值),但目前没有表示任意类型变异的方法(例如,类型
string
的值被更改为类型
number
的值)

即将到来的(预定的)应该至少允许在类型系统中表示这种缩小,这样您就可以将
func(4)
shorrow
func
从type
IMyfunc
转换为
IMyfunc
。但是你仍然可能无法进行你正在寻找的任意突变。从
IMyfunc
更改为
IMyfunc
并没有缩小范围;你必须首先以某种方式扩展回
IMyfunc
,我认为没有任何方法可以做到这一点

类似于您的用例的内容将在中讨论,而不能后退的问题是。也许最终这是可行的,或者类似的事情?不确定


在任何情况下,静态类型系统的主要驱动因素之一是表达式具有一个静态类型,该静态类型表示它可以接受的一组可能值,并且静态类型不会更改。这与函数式编程技术配合得很好,函数式编程技术支持无状态性和不变性,通常在命令式编程可能改变现有值的情况下返回新值

如果我们更改代码以执行此操作,您将得到以下内容:

type Func<T> = {
  userId: T;
  <U>(item: U): Func<U>;
};
这种实现是无状态的;它从不修改自身或传入的项。您可以这样使用它:

func(4);
const n = func.userId; // n inferred as number
func("a");
const s = func.userId; // s inferred as string
func(false);
const b = func.userId; // b inferred as boolean
function func<U>(item: U): Func<U> {
  const f = <T>(item: T) => func(item);
  return Object.assign(f, { userId: item });
}
const f = func(4);
const n = f.userId; // number
console.log(n); // 4
function func<U>(item: U): { userId: U } {
  return { userId: item };
}

const f = func(4);
const n = f.userId; // 4
console.log(n); // 4

const g = func("a");
const s = g.userId; // string
console.log(s); // 1

const h = func(false);
const b = h.userId; // boolean
console.log(b); // false
然后使用
f
而不是
func

const g = f("a");
const s = g.userId; // string
console.log(s); // 1
当然,在上述实现中,您可以重用
func()
,因为它是无状态的:

const h = func(false);
const b = h.userId; // boolean
console.log(b); // false
这样的话,你就不需要这么复杂了。。。您只需实现如下代码:

func(4);
const n = func.userId; // n inferred as number
func("a");
const s = func.userId; // s inferred as string
func(false);
const b = func.userId; // b inferred as boolean
function func<U>(item: U): Func<U> {
  const f = <T>(item: T) => func(item);
  return Object.assign(f, { userId: item });
}
const f = func(4);
const n = f.userId; // number
console.log(n); // 4
function func<U>(item: U): { userId: U } {
  return { userId: item };
}

const f = func(4);
const n = f.userId; // 4
console.log(n); // 4

const g = func("a");
const s = g.userId; // string
console.log(s); // 1

const h = func(false);
const b = h.userId; // boolean
console.log(b); // false
函数func(项:U):{userId:U}{
返回{userId:item};
}
常数f=func(4);
const n=f.userId;//4.
console.log(n);//4.
常数g=func(“a”);
const s=g.userId;//一串
控制台。日志;//1.
常数h=func(假);
const b=h.userId;//布尔值
控制台日志(b);//假的
在这一点上,我已经解释了这种情况,因为您刚刚得到了一个返回包装对象的函数。我可能会推荐这种方法,而不是任何带有变异的方法,因为它更适合于类型系统。但是你比我更了解你的用例


无论如何,希望这有帮助;祝你好运


使用const func:IMyfunc=a=>a可以实现所谓的“真正的泛型”,但会失去类型安全性。Typescript需要在分配value@DPro是的,所以我想知道有没有什么方法可以让这种函数真正的通用化,而不会失去类型安全性。嗯,你能看一下用例吗?假设我有一个名为
func
的“真正的泛型”值。我知道如果你调用
func(3)
你会得到一个
号码,如果你调用
func(“a”)
你会得到一个
字符串,但是
func.userId
的类型是什么?@jcalz-emm,如果实现是
const-func:IMyfunc=a=>{func.userId=a;return a}
,可能对你的用例有意义。每次调用
func
时,
func.userId
应该是
func
的参数类型。您需要的是“类型状态”或“类型变异”,其中值的类型可以根据值的使用方式进行更改。TypeScript可以通过控制流分析缩小某些值的类型,但目前还没有表示任意类型变异的方法。接下来的代码更接近,但仍然不会按您想要的方式“堆叠”(可能您想要
func(0);const a=func.userId;func(“a”);const b=func.userId
来推断
a
number
b
string
,但是
b
可能永远不会
。调用时出错