Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typescript/9.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 我怎样才能有一个“做一个不完整的类型”<;Foo>;但是传递的引用只包括来自Foo的键_Typescript - Fatal编程技术网

Typescript 我怎样才能有一个“做一个不完整的类型”<;Foo>;但是传递的引用只包括来自Foo的键

Typescript 我怎样才能有一个“做一个不完整的类型”<;Foo>;但是传递的引用只包括来自Foo的键,typescript,Typescript,假设我有 class Foo { readonly a!: string readonly b!: string readonly c!: string } 然后我创建了一个带有参数的方法 Partial<Foo> 我可以将Bar传递给采用Partial的方法,但这不是我想要的 我想要的是某种类型的AllowOnlyKeys from,您仍然可以有0个键,或1个键,或所有键,但是Bar不匹配,因为它有一个不在foo中的键 我尝试过使用许多库,包括ts ess

假设我有

class Foo {
   readonly a!: string
   readonly b!: string
   readonly c!: string
}
然后我创建了一个带有参数的方法

  Partial<Foo>
我可以将
Bar
传递给采用
Partial
的方法,但这不是我想要的

我想要的是某种类型的
AllowOnlyKeys from
,您仍然可以有0个键,或1个键,或所有键,但是
Bar
不匹配,因为它有一个不在foo中的键

我尝试过使用许多库,包括
ts essentials
ts typedefs
,以及
ts toolbelt
,但还没有找到解决方案

它们是否有任何方法可以获得我想要的行为,这样编译器就可以防止我将完全错误的对象传递给
mymethod(part:Partial)

您想要的对象,而这些对象在TypeScript中并不存在。TypeScript中的对象类型被认为是“开放的”或“可扩展的”;像
{a?:string,b?:string,c?:string}
这样的类型只指定
a
b
c
键处的属性类型。它根本不禁止使用其他键。所以像
{a:,b:,c:,d:12345}
这样的值是有效的。因此,
是有效的
部分

请注意,这通常是一个理想的功能,因为它允许
接口
扩展:

interface X {
    x: string;
}
interface Y extends X {
    y: number;
}
这里,
Y扩展X
意味着每个
Y
都是一个
X
。这直接导致了你不满意的过度房产扩张:

const y: Y = { x: "", y: 1 }
const x: X = y; // okay
有一些近似于精确类型的变通方法,这些方法对于您的目的来说可能表现得足够好,但都可以避免,因为编译器总是允许您将值扩展到不知道有问题的键的类型


我首选的解决方法是在
部分
中创建
myMethod()
,类似于
部分
的类型
T
。您可以
T
,这样其中的每个已知属性都需要是
Foo
中的属性,如果有任何额外属性,则它们必须是
从不
。像这样:

mymethod<T extends { [K in keyof T]: K extends keyof Foo ? Foo[K] : never }>(
    part: T
) { 
    console.log(part);
}
万岁,它阻止了
!如果您将对象交给
mymethod
,这非常好,因为已知这些对象具有多余的属性。但没有什么能阻止这一点:

const partialFoo: Partial<Foo> = bar; // valid assignment
obj.mymethod(partialFoo); // no error!
然后制作一个版本的
mymethod()
,在对其进行操作之前,从
零件
中提取
a
b
c
属性:

mySafeMethod(part: Partial<Foo>) {
    this.mymethod(pluck(part, "a", "b", "c"));
}
运行时代码期望
部分
可能比
a
b
c
具有更多属性,并显式忽略它们,而不是使用
对象.keys()
for.
迭代所有现有键。这可能不是惯用的JavaScript,但它确实使编译器更容易处理


好的,希望这些想法中的一个能帮助你;祝你好运


更新

TypeScript并不能真正“获取”确切的类型,尤其是未指定的泛型类型,就像您在
mymethod
的实现中看到的那样。因此在
mymethod
中,编译器对
part
知之甚少。有很多方法可以解决这个问题。。。一种更丑陋的方法是将精确类型与开放类型相交,这样编译器至少可以知道
T
是一个
部分
以及其他它无法验证的内容:

mymethod<T extends Partial<Foo> & 
  { [K in keyof T]: K extends keyof Foo ? Foo[K] : never }
>(
    part: T
) {
    console.log(part);
    part.b?.toUpperCase(); // okay
}
mymethod(
第部分:T
) {
控制台日志(部分);
part.b?.toUpperCase();//好的
}
这对你有用吗


@jcalz的答案很好,但不是我最终实现的,而是它引导我实现的

type FooPart = Opaque<Partial<Foo>>;
在哪里


将失败。

可能与此相关。我尝试了顶部答案中的
NoExtraProperties
,但是
Partial
类型阻止它按预期工作。该页面上涉及鉴别器属性的其他解决方案可能是您的最佳选择。如果
mymethod
出现问题,访问方法内部的属性会导致编译时失败。是的,这是可行的。。。。我得弄清楚如何把那一长串代码变成泛型类型。。。我还有一些其他的问题。。。这可能在内部通过强制转换解决…您可以始终使用重载将调用签名与实现签名分离,如
mymethod(part:T):void
用于调用签名,然后
mymethod(part:Partial){…}
用于实现
mySafeMethod(part: Partial<Foo>) {
    this.mymethod(pluck(part, "a", "b", "c"));
}
obj.mySafeMethod(bar); // { a: "" };
mymethod<T extends Partial<Foo> & 
  { [K in keyof T]: K extends keyof Foo ? Foo[K] : never }
>(
    part: T
) {
    console.log(part);
    part.b?.toUpperCase(); // okay
}
type FooPart = Opaque<Partial<Foo>>;
foo(): Foo { 
   return { a: 'test' } as FooPart;
}
foo(): Foo { 
   return { a: 'test', d: 'not valid' } as FooPart;
}