- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我得到:
Overload signature is not compatible with function implementation.ts(2394)
开启:
/** Iterate through an Array. */
export default function eachr<Value>(
subject: Array<Value>,
callback: IteratorCallback<typeof subject, number, Value>
): typeof subject
整个片段:
export interface IteratorCallback<Subject, Key, Value> {
(this: Subject, value: Value, key: Key, subject: Subject): void | boolean
}
/** Iterate through an Array. */
export default function eachr<Value>(
subject: Array<Value>,
callback: IteratorCallback<typeof subject, number, Value>
): typeof subject
/** Iterate through an Object. */
export default function eachr<RecordKey extends keyof any, Value>(
subject: Record<RecordKey, Value>,
callback: IteratorCallback<typeof subject, RecordKey, Value>
): typeof subject
/** Iterate through the subject. */
export default function eachr<RecordKey extends keyof any, Value>(
input: Array<Value> | Record<RecordKey, Value>,
callback: IteratorCallback<typeof input, RecordKey | number, Value>
): typeof input {
if (Array.isArray(input)) {
// Array
const subject = input as Array<Value>
for (let key = 0; key < subject.length; ++key) {
const value = subject[key]
if (callback.call(subject, value, key, subject) === false) {
break
}
}
} else {
// Object
const subject = input as Record<RecordKey, Value>
for (const key in subject) {
if (subject.hasOwnProperty(key)) {
const value = subject[key]
if (callback.call(subject, value, key, subject) === false) {
break
}
}
}
}
// Return
return input
}
我可以通过将其更改为:
/** Iterate through an Array. */
export default function eachr<Subject extends Array<Value>, Value>(
subject: Subject & Array<Value>,
callback: IteratorCallback<typeof subject, number, Value>
): typeof subject
但是,我不明白为什么会修复它。问题是什么,为什么该更改使问题消失了?
更令我惊讶的是,如果我将相同的更改应用于纯对象迭代器函数,它会导致它失败:
/** Iterate through an Object. */
export default function eachrObject<
Subject extends Record<RecordKey, Value>,
RecordKey extends keyof any,
Value
>(
subject: Subject & Record<RecordKey, Value>,
callback: IteratorCallback<typeof subject, RecordKey, Value>
): typeof subject {
for (const key in subject) {
if (subject.hasOwnProperty(key)) {
const value = subject[key]
// above fails with: Element implicitly has an 'any' type because type 'Record<RecordKey, Value>' has no index signature.ts(7017)
// below fails with: Argument of type 'string' is not assignable to parameter of type 'RecordKey'.ts(2345)
if (callback.call(subject, value, key, subject) === false) {
break
}
}
}
return subject
}
虽然这是可行的:
/** Iterate through an Object. */
export default function eachrObject<RecordKey extends keyof any, Value>(
subject: Record<RecordKey, Value>,
callback: IteratorCallback<typeof subject, RecordKey, Value>
): typeof subject {
for (const key in subject) {
if (subject.hasOwnProperty(key)) {
const value = subject[key]
if (callback.call(subject, value, key, subject) === false) {
break
}
}
}
return subject
}
然而这两种形式都适用于数组迭代器:
/** Iterate through an Array. */
export default function eachrArray<Subject extends Array<Value>, Value>(
subject: Subject & Array<Value>,
callback: IteratorCallback<typeof subject, number, Value>
): typeof subject {
for (let key = 0; key < subject.length; ++key) {
const value = subject[key]
if (callback.call(subject, value, key, subject) === false) {
break
}
}
return subject
}
/** Iterate through an Array. */
export default function eachrArray<Value>(
subject: Array<Value>,
callback: IteratorCallback<typeof subject, number, Value>
): typeof subject {
for (let key = 0; key < subject.length; ++key) {
const value = subject[key]
if (callback.call(subject, value, key, subject) === false) {
break
}
}
return subject
}
那么为什么会变成Subject extends Array<Value>
呢?对于区域迭代器的重载兼容性是必需的,但 Subject extends Record<RecordKey, Value>
破坏对象迭代器?
抱歉,这里的代码量太大了,这是我可以归结为的最小用例,其中包含了所有的考虑因素。
最佳答案
老实说,这需要费力地解决很多问题,而且我认为我无法准确回答您为什么让这些东西发挥作用。在我看来,您的过载签名都应该失败。让我们看一个 super 简单的重载/实现示例:
function foo(x: string): void; // narrower, okay
function foo(x: string | number | boolean): void; // wider, error
function foo(x: string | number): void {} // impl
注意第二个重载签名如何给出与实现签名不兼容的错误。那是因为过载的 x
是比实现的 x
类型更宽的类型.并且重载需要更窄的类型。
还要注意一般情况下(自 --strictFunctionTypes
was introduced in TypeScript 2.6 起)函数类型在它们的参数类型中是如何逆变的。这会导致以下行为:
type StringAccepter = (x: string) => void;
const helloAccepter: StringAccepter = (x: "hello") => {}; // error
const stringOrNumberAccepter: StringAccepter = (x: string | number) => {}; // okay
helloAccepter
不是有效的 StringAccepter
因为"hello"
比 string
窄, 而 stringOrNumberAccepter
是一个有效的StringAccepter
因为string | number
比 string
宽.因此,函数参数变宽会使它们的函数变窄,反之亦然:
function bar(cb: (x: "hello")=>void): void; // error, cb is too wide because x is too narrow
function bar(cb: (x: string | number)=>void): void; // okay, cb is narrower because x is wider
function bar(cb: StringAccepter): void {} // impl
所以我预计你的两个重载都会失败,因为实现签名的 callback
类型( IteratorCallback<typeof input, RecordKey | number, Value>
)实际上比您的任何一个调用签名的 callback
都窄类型。
在这一点上,与其尝试通过涉及额外 Subject
的可能解决方案苦苦挣扎类型参数并理解为什么有些东西起作用而有些东西不起作用(这让我的大脑受伤......也许有编译器错误?也许不是?谁知道),我会改为使用我建议的解决方案...... . 使实现签名真正足够宽以支持两种调用签名:
/** Iterate through an Array. */
export function eachr<Value>(
subject: Array<Value>,
callback: IteratorCallback<typeof subject, number, Value>
): typeof subject
/** Iterate through an Object. */
export function eachr<RecordKey extends keyof any, Value>(
subject: Record<RecordKey, Value>,
callback: IteratorCallback<typeof subject, RecordKey, Value>
): typeof subject
/** Iterate through the subject. */
export function eachr<RecordKey extends keyof any, Value>(
input: Array<Value> | Record<RecordKey, Value>,
// here is the change
callback: IteratorCallback<Array<Value>, number, Value> |
IteratorCallback<Record<RecordKey, Value>, RecordKey, Value>
): typeof input {
if (Array.isArray(input)) {
// Array
const subject = input as Array<Value>
// a new assertion:
const cb = callback as IteratorCallback<Array<Value>, number, Value>;
for (let key = 0; key < subject.length; ++key) {
const value = subject[key]
if (cb.call(subject, value, key, subject) === false) {
break
}
}
} else {
// Object
const subject = input as Record<RecordKey, Value>
// a new assertion:
const cb = callback as IteratorCallback<Record<RecordKey, Value>, RecordKey, Value>;
for (const key in subject) {
if (subject.hasOwnProperty(key)) {
const value = subject[key]
if (cb.call(subject, value, key, subject) === false) {
break
}
}
}
}
// Return
return input
}
区别在于 callback
实现签名上的参数是 callback
的类似类型的真正联合每个调用签名上的参数。此外,实现本身需要对 callback
进行缩小断言。至 cb
与您已经为 input
所做的断言的方式大致相同至 subject
.
现在编译器应该很高兴了。希望有所帮助;祝你好运!
关于typescript - 为什么兼容的重载签名需要 `Subject & Array<Value>`?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54008406/
如果 Subject 继承自 Observable,那么基于任何 Subject 的下一个选项有什么区别,例如: private val locationSubject: ReplaySubject
关闭。这个问题需要debugging details .它目前不接受答案。 编辑问题以包含 desired behavior, a specific problem or error, and th
我正在尝试从内部使用 Rx.Subject 的函数返回一个可观察对象。当然,与任何好的 API 一样,实现细节应该完全从消费者那里抽象出来。但是,使用 Subject.asObservable() 似
我使用 angular2 rxjs 来测试它的多播功能,这是我的代码: var source = Observable.from([1, 2, 3]); var subject = new Subje
我需要一个可以显示每个主题的最高分数计数的查询。假设 3 名学生的科学成绩需要达到 98 分 count marks subject 3 98 Maths 最佳答案 首先找到每个
我正在使用JavaFX 11(OpenFX)运行一些应用程序。该应用程序是用IntellijIdea编写的,并使用gradle构建。在IDE中运行时,一切正常。构建jar时,它构建成功,但是当我尝试执
我继承自模板类。当我进入教师类(class)时,我想进入学科类(class),反之亦然。我收到错误 Invalid use of incomplete type struct Subect; void
Angular 2 和 Typescript 应用。 我在 NPM 包中有一个抽象类,我试图在我的应用程序代码中提供实现。这一切都很好,直到我添加了公众 isLoggedIn:Subject;属性(p
我从 this tutorial 中提取了示例模板代码并执行以下两个步骤开始 - npm install//工作正常并创建了包含所有依赖项的 node_modules 文件夹 npm 开始//失败并出
我需要答案来显示最低分和最高分,同时给出正确的主题 import java.util.Scanner; //import package class Task11 { public stati
如果我的这个类有一个在其生命周期中发出单一值的主题: export class MyClass { myEmitter$: Subject = new Subject(); someMetho
我正在尝试用 ionic 制作一个小应用程序,但是当我从 UI 调用 $scope.saveClass() 函数时它给了我这个错误。 无法获取未定义或空引用的属性“subject” 我不明白,因为他不
背景 我有一个核心数据实体 Entry 与另一个实体 DataField 有关系: class Entry: NSManagedObject { //[...] @NSManaged
我知道这个问题更像是一个语法问题,但是如果你有一组 Penn Treebank 标记,你如何确定句子的“主题”,例如: [WP][VBZ][DT][NN] 是否有任何 Java 库可以接收此类标记并确
我使用 SwiftUI 构建了一个 LoadingView,用于在我从 API 获取远程数据时显示我的应用程序中的一些加载内容。我正在使用 Xcode 版本 11.0 beta 5。 这是Loadin
Subjects 介绍 1. Subjects 是订阅者,也是Observable 订阅者:它能动态的接收新的值。 Observable: 当Subjects有了新值后会通过Event将新值发
关闭。这个问题不满足Stack Overflow guidelines .它目前不接受答案。 想改善这个问题吗?更新问题,使其成为 on-topic对于堆栈溢出。 8年前关闭。 Improve thi
我需要了解主题在 Weblogic 中如何存储和传播。 经过身份验证后,主题存储在 HTTP 层的哪里?在内部,它存储在 HTTPSession 中吗? 同理,EJB层存储在哪里? 我有一个应用程序,
我经常遇到这样的情况,我想要一个 UI 元素来“观察”一个基础值——假设我正在显示一个 int——我想要一个我可以订阅的 IObservable。 我下面一直用的是Subject,直接设置就可以了
我有一个简单的服务。 import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export cl
我是一名优秀的程序员,十分优秀!