- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
考虑到广泛共享的类型省略,定义如下:
type Omit<ObjectType, KeysType extends keyof ObjectType> =
Pick<ObjectType, Exclude<keyof ObjectType, KeysType>>;
T
其中一个属性丢失,然后设置缺失的属性并返回一个类型
T
的值。
type A = { x: string }
function f(arg: Omit<A, 'x'>): A {
return { ...arg, x: "" }
}
function g<T extends A>(arg: Omit<T, 'x'>): T {
return { ...arg, x: "" }
}
g
定义的错误是:
Pick<T, Exclude<keyof T, "x">> & { x: string; }
可分配给
T
。
最佳答案
警告,请回答。总结:
潜在的问题是known但可能看不到太大的吸引力
简单的修复是使用类型断言return { ...arg, x: "" } as T;
简单的修复并不是完全安全的,在一些边缘的情况下会有坏的结果
无论如何,g()
不能正确地推断出T
。
底部的重构g()
函数可能更适合您
我需要停止写这么多东西
这里的主要问题是编译器只是不够聪明,无法验证泛型类型的某些等价性。
// If you use CompilerKnowsTheseAreTheSame<T, U> and it compiles,
// then T and U are known to be mutually assignable by the compiler
// If you use CompilerKnowsTheseAreTheSame<T, U> and it gives an error,
// then T and U are NOT KNOWN to be mutually assignable by the compiler,
// even though they might be known to be so by a clever human being
type CompilerKnowsTheseAreTheSame<T extends U, U extends V, V=T> = T;
// The compiler knows that Picking all keys of T gives you T
type PickEverything<T extends object> =
CompilerKnowsTheseAreTheSame<T, Pick<T, keyof T>>; // okay
// The compiler *doesn't* know that Omitting no keys of T gives you T
type OmitNothing<T extends object> =
CompilerKnowsTheseAreTheSame<T, Omit<T, never>>; // nope!
// And the compiler *definitely* doesn't know that you can
// join the results of Pick and Omit on the same keys to get T
type PickAndOmit<T extends object, K extends keyof T> =
CompilerKnowsTheseAreTheSame<T, Pick<T, K> & Omit<T, K>>; // nope!
interface Concrete {
a: string,
b: number,
c: boolean
}
// okay now
type OmitNothingConcrete =
CompilerKnowsTheseAreTheSame<Concrete, Omit<Concrete, never>>;
// nope, still too generic
type PickAndOmitConcrete<K extends keyof Concrete> =
CompilerKnowsTheseAreTheSame<Concrete, Pick<Concrete, K> & Omit<Concrete, K>>;
// okay now
type PickAndOmitConcreteKeys =
CompilerKnowsTheseAreTheSame<Concrete, Pick<Concrete, "a"|"b"> & Omit<Concrete, "a"|"b">>;
T
实现它,这不会自动实现。
function g<T extends A>(arg: Omit<T, 'x'>): T {
return { ...arg, x: "" } as T; // no error now
}
U
,它意味着要么持有
a
属性,要么持有
b
属性,这取决于
x
属性的
string literal值:
// discriminated union U
type U = { x: "a", a: number } | { x: "b", b: string };
declare const u: U;
// check discriminant
if (u.x === "a") {
console.log(u.a); // okay
} else {
console.log(u.b); // okay
}
U
扩展了
A
,因为
U
类型的任何值也应该是
A
类型的值。这意味着我可以像这样调用
g
:
// notice that the following compiles with no error
const oops = g<U>({ a: 1 });
// oops is supposed to be a U, but it's not!
oops.x; // is "a" | "b" at compile time but "" at runtime!
{a: 1}
可分配给
Omit<U, 'x'>
,因此编译器认为它生成了类型为
oops
的值
U
。但它不是,是吗?你知道,
oops.x
也不是
"a"
,而是
"b"
。我们对编译器撒了谎,现在我们开始使用
""
时会遇到麻烦。
oops
函数作为类型永远无法推断出一个比
g()
窄的类型。如果调用
T
,
A
将被推断为
g({a: 1})
。如果
T
总是被推断为
A
,那么您甚至可能没有泛型函数。
T
足够理解它如何与
A
一起形成
Omit<T, 'x'>
,所以它不能进入类型
Pick<T, 'x'>
的值,并找出
T
应该是什么。那么我们能做些什么呢?
function g<T>(arg: T) {
return { ...arg, x: "" };
}
Omit<T, 'x'>
将获取
T
类型的值并返回
g()
类型的值。这将始终可以分配给
T
,因此您应该可以使用它:
const okay = g({a: 1, b: "two"}); // {a: number, b: string, x: string}
const works: A = okay; // fine
T & {a: string}
具有
A
属性,那还没有发生:
const stillWorks = g({x: 1});
function g<T extends { [K in keyof T]: K extends 'x' ? never : T[K] }>(arg: T) {
return { ...arg, x: "" };
}
const breaksNow = g({x: 1}); // error, string is not assignable to never.
关于typescript - 省略类型往返不适用于泛型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55299469/
这是我在这里的第一篇文章,也是我第一次使用 C++。我正在查看从 Internet 获得的一些代码,但我对此有疑问。 它有一个 for 循环,像这样: for(cin >> t;t--;) 我明白它在
我目前正在开发一个网站,除其他外,该网站允许用户通过显示或隐藏他们已购买的商品来过滤市场。这适用于基本的 AJAX 调用,该调用传递可用过滤器的当前条件,然后使用 CodeIgniter 的事件记录构
我创建了一个 MWE,其中通过添加 来更改单行解决编译器错误。 以下代码无法编译: import java.util.List; public class MainClass { publi
当我想测试一些 PostgreSQL 函数 FOO() 的行为时,我发现执行类似 SELECT FOO(bar) 的查询很有用,bar一些数据我用作直接输入,而无需从真实表中SELECT。 我读到我们
在 PHP、Java、C++(以及许多其他语言)中,for 循环是这样使用的: for(int i=0;i<10;i++) 如果我已经初始化了i,我该如何省略初始化语句呢? 最佳答案 在 Java、C
我发现我们的 Android 应用出现了一个奇怪的问题,特别是在 4.4 版的 Moto X 上。 在偏好 Activity 中,所有标题的前 8 个字符都在开头用省略号截断。这也发生在溢出菜单和整个
我有一个 XElement,我必须解析它以删除结束标记中的空白。我的代码如下所示: var stringBuilder = new StringBuilder(); using (var string
假设我有两个接口(interface),X和 Y ,它们共享一些字段,但也有独立的字段: interface X { abc: number; foo: number; bar: numb
我有这个模型: var accountSchema = new mongoose.Schema({ 'seeker': { 'fullName': String,
我在 R 中运行一个具有大量时间和位置固定效应的回归。我尝试将一个漂亮的汇总表输出到 Latex 中。我从 stargazer 包切换到 huxtable,因为 stargazer 在忽略固定效果时表
假设我有一个数据框: a df a b c d 1 0 9 10 2 1 10 13 3 NA 11 14 4 3 NA 7 5 4 13 22 现在假设我
我在 R 中运行一个具有大量时间和位置固定效应的回归。我尝试将一个漂亮的汇总表输出到 Latex 中。我从 stargazer 包切换到 huxtable,因为 stargazer 在忽略固定效果时表
我想删除一个属性并返回一个新对象而不改变原始对象。 我知道我们可以像这样使用 Lodash 轻松做到这一点: const profile = { name: 'Maria', age: 30 } _.
我正在通过更改一些内容来修改 javascript 对象。当我重新创建它时,我会得到每个 key 对的索引号。 "0":{...},"1":{...}, 如何删除/省略这些 0、1、2、3、4 数字的
我正在一个非常方便且名称丰富的网站 here 上完成示例之一。 ,具体来说: func applyMutliplication(value: Int, multFunction: Int -> Int
这个问题在这里已经有了答案: Why do java source files require package declarations? (4 个答案) 关闭 6 年前。 我是 Java 的新手,
在下面的代码中: Widget makeWidget() { return Widget(); } void foo(Widget widget) { ... } foo(makeWid
这是我使用下面的调用调用的过程: CALL abc('01-04-2011','14-04-2014','28,29,36,37,38','33,34,35,41,42,43') 但问题是下面提到的查
嘿,我正在寻找一种在 yui 数据表中省略文本的好方法。我的意思是,格式化文本,使其很好地适合其单元格,并且如果文本必须被 chop ,则在其后面有一个椭圆 (...)。 我想在不使用 CSS 选择器
我有一个如下表(记录)。 ID Status AA124 Pass AA125 Pass Z_AA134 Fail Z_AA135
我是一名优秀的程序员,十分优秀!