天道酬勤,学无止境

{...} 类型的参数不可分配给“从不”类型的参数(Argument of type {...} is not assignable to parameter of type 'never')

问题

我正在尝试基于另一个具有相同键的类型创建一个类型,其值的类型基于但不等于另一种类型。 它类似于ReactsetState ,它接受一个值或一个获取当前值并返回一个新值的函数。

经过研究,与此错误相关的所有问题似乎都与缺少类型提示有关。 我已经尝试为所有nextcurrentnewTheme[key]变量指定类型。 它没有用。

type Mode = "light" | "dark";

interface Theme {
  mode: Mode;
  test: number;
}

type ThemeUpdate = {
  [K in keyof Theme]: Theme[K] | ((current: Theme[K]) => Theme[K])
};

const reducer = (currentTheme: Theme, action: Partial<ThemeUpdate>): Theme => {
  const newTheme: Partial<Theme> = {};

  (Object.keys(action) as (keyof Theme)[]).forEach((key: keyof Theme) => {
    const next = action[key];
    const current = currentTheme[key];
    newTheme[key] = typeof next === "function" ? next(current) : next;
    //                                                ^^^^^^^
    // Argument of type 'number | "light" | "dark"' is not assignable to parameter of type 'never'. Type 'number' is not assignable to type 'never'
  });

  return { ...currentTheme, ...newTheme };
};

我期望next函数将根据当前键解析参数类型。 相反,参数被解析为类型never并且我收到错误消息:

'number 类型的参数 | “光” | “dark”' 不能分配给“never”类型的参数。 “数字”类型不能分配给“从不”类型

key === "mode"next函数应该将current参数推断为Mode ,当key === "test"它应该推断为number

回答1

是的,这是 TypeScript 中我一直称之为相关类型的痛点之一。 问题是您有一组相互不独立的联合类型值。 nextcurrent关联方式取决于key的值。 但是 TypeScript 只是将next视为 values-or-functions-or-undefined(这是正确的)的并集,将current视为值的并集(这也是正确的),而没有意识到next不可能对应于"mode"并使current同时对应于"test" 。 对调用函数联合的改进支持只会使这个问题更加混乱,因为never交集并没有提供关于发生了什么的太多线索。

这里没有很好的解决方案。 我发现处理这个问题的方法是手动引导编译器处理不同的情况,如下所示:

  (Object.keys(action) as (keyof Theme)[]).forEach(key => {
    switch (key) {
      case "mode": {
        const next = action[key];
        const current = currentTheme[key];
        newTheme[key] = typeof next === "function" ? next(current) : next; // okay
        break;
      }
      case "test": {
        const next = action[key];
        const current = currentTheme[key];
        newTheme[key] = typeof next === "function" ? next(current) : next; // okay
        break;
      }
    }
  });

这是非常类型安全的,但很乏味......

或者,您将需要在某处进行类型断言以说服编译器您正在做的事情是安全的(这是承担安全责任;编译器正在放弃)。 对于这个特定问题,我会考虑使forEach()回调成为键类型K的通用函数,然后使用您的断言告诉编译器next以它理解的方式依赖于K

  (Object.keys(action) as (keyof Theme)[]).forEach(
    // generic
    <K extends keyof Theme>(key: K) => {
      const next = action[key] as  // assert here
        | Theme[K]
        | ((current: Theme[K]) => Theme[K])
        | undefined;
      const current = currentTheme[key];
      newTheme[key] = typeof next === "function" ? next(current) : next; // okay
    }
  );

这更方便但不安全。

我通常在这里推荐断言(代码链接),并希望有一天能在 TypeScript 中引入对相关类型的更好支持。

好的,希望有帮助。 祝你好运!

标签

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • 打字稿错误:“对象”类型的参数不可分配给“{}[]”类型的参数(Typescript error: Argument of type 'Object' is not assignable to parameter of type '{}[]')
    问题 我正在使用 Angular Material 表组件,如下所示: this.userService.getUsers().subscribe((response) => { this.users = new MatTableDataSource(response); }); 它可以工作,但在编译时会引发以下打字稿错误: “Object”类型的参数不可分配给“{}[]”类型的参数。 “对象”类型可分配给很少的其他类型。 您的意思是改用“任何”类型吗? “对象”类型中缺少属性“包含”。 所以我尝试将其更改为: this.users = new MatTableDataSource<any>(response); 但还是同样的错误。 response如下所示: [{ userId: 123, username: 'Tom' }, { userId: 456, username: 'Joe' }] 知道如何摆脱错误吗? 编辑 应该提到如果我这样做: this.users = new MatTableDataSource([response]); 错误消失了,但是表格不起作用,因为格式不是表格所期望的正确格式。 只是注意到这一点,以防万一它揭示了可能是什么原因...... 回答1 “Object”类型的参数不可分配给“{}[]”类型的参数。
  • 'string | 类型的参数 null' 不可分配给类型为 'ValueFn 的参数 '(Argument of type 'string | null' is not assignable to parameter of type 'ValueFn<SVGPathElement, Datum[], string | number | boolean | null>')
    问题 我是 d3 的新手,并尝试使用 d3、TypeScript 和 react 来实现最小折线图。 但它总是会导致 TypeScript 错误。 在我的图表被错误消息替换之前,我什至会看到一秒钟的图表。 我尽可能将 d3 部分与 react 代码分开。 有一个反应组件,它用一个id渲染一个div ,在componentDidUpdate , id被传递给一个单独的文件中的draw函数,其中包含我所有的 d3 代码(下面的代码)。 我试图为所有可以输入的东西提供一个类型。 import * as d3 from 'd3' type Props = { id: string } type Datum = {x: number, y: number} type Data = Array<Datum> const draw = (props: Props) => { const data = [ { x: 1, y: 5 }, { x: 20, y: 20 }, { x: 40, y: 10 }, { x: 60, y: 40 }, { x: 80, y: 5 }, { x: 100, y: 60 }, ] const container = d3.select<HTMLElement, any>('#' + props.id) container.selectAll
  • “(e: CustomEvent) => void”类型的参数不可分配给“EventListenerOrEventListenerObject”类型的参数(Argument of type '(e: CustomEvent) => void' is not assignable to parameter of type 'EventListenerOrEventListenerObject')
    问题 我有这个自定义事件设置,它适用于 TypeScript 2.5.3 ,但是当我更新到2.6.1出现错误 window.addEventListener('OnRewards', (e: CustomEvent) => { // my code here }) [ts] '(e: CustomEvent) => void' 类型的参数不可分配给 'EventListenerOrEventListenerObject' 类型的参数。 类型 '(e: CustomEvent) => void' 不能分配给类型 'EventListenerObject'。 类型 '(e: CustomEvent) => void' 中缺少属性 'handleEvent'。 我不确定在这里做什么来解决这个问题。 回答1 这是由于 TypeScript v2.6 中添加的 --strictFunctionTypes 编译器标志的行为。 类型为(e: CustomEvent) => void函数不再被视为EventListener的有效实例,它采用Event参数,而不是CustomEvent 。 因此,修复它的一种方法是关闭--strictFunctionTypes 。 另一种方法是传入一个函数,该函数接受一个Event ,然后通过类型保护缩小到CustomEvent : function
  • 类型参数不可分配给字符串(Argument of type is not assignable to string)
    问题 我有一个格式化的 json 数据,我想在 d3 中使用它来绘制层次结构。 它正在处理旧数据,但在 json 数据中添加更多维度后,出现以下错误。 '{ name: string; 类型的参数儿童:{组:编号; 名称:字符串; }[]; 组:数量; }[]' 不能分配给类型为 'readonly string[]' 的参数。 输入'{名称:字符串; 儿童:{组:编号; 名称:字符串; }[]; 组:数量; }' 不可分配给类型 'string'。 我重新格式化的数据的输出如下,它是通过使用@Dacre Denny's answer from Change Json data into new format by JavaScript link 中的代码生成的 { name: "program", children: (1)[ { name: "file1", children: (1)[ { name: "function1", calls: (2)[ { line: 105, file: "file2", function: "function5" }, { line: 106, file: "file2", function: "function6" } ], point: (2)[ 102, 105 ], point2: (3)[ (2)[ 102, 102 ], (3)
  • '(snap: DataSnapshot) => void' 类型的参数不可分配给类型 '(a: DataSnapshot) => boolean' 的参数(Argument of type '(snap: DataSnapshot) => void' is not assignable to parameter of type '(a: DataSnapshot) => boolean')
    问题 我已经阅读了有关此问题的几个问题和答案,但无法解决。 我正在使用 Ionic2,并且有一种方法可以从 Firebase 数据库 v3 中检索数据。 我不明白为什么在执行ionic serve时会在控制台中出现以下错误: Error TS2345: Argument of type '(snap: DataSnapshot) => void' is not assignable to parameter of type '(a: DataSnapshot) => boolean'. Type 'void' is not assignable to type 'boolean'. 这是方法: constructor(private http: Http) { firebase.database().ref('users').orderByChild("id").on("value", function(snapshot){ let items = []; snapshot.forEach(snap => { items.push({ uid: snap.val().uid, username: snap.val().username, }); }); }); } } 回答1 DataSnapshot的forEach方法具有以下签名: forEach(action: (a
  • Angular 2 引导函数给出错误“参数类型 AppComponent 不可分配给参数类型类型”(Angular 2 bootstrap function gives error “Argument type AppComponent is not assignable to parameter type Type”)
    问题 这是我来自 Angular 2 快速入门指南的第一个简单的Hello World angular 2 应用程序。 import {Component} from 'angular2/core'; import {bootstrap} from 'angular2/platform/browser'; @Component({ selector: 'ng2-app', template: '<h1>My first Angular 2 App</h1>' }) export class AppComponent { } bootstrap(AppComponent); 当我使用npm start运行时,应用程序运行良好,但我的 IntelliJ IDE 在bootstrap(AppComponent)行中显示错误 参数类型AppComponent不可分配给参数类型Type 查看bootstrap函数声明, AppComponent需要扩展Type 。 export declare function bootstrap(appComponentType: Type, customProviders?: Array<any>): Promise<ComponentRef>; 我的问题是: Angular 组件是否可以扩展Type ? 回答1 实际上, AppComponent
  • “X”类型的参数不能分配给“X”类型的参数(Argument of type 'X' is not assignable to parameter of type 'X')
    问题 再会。 我是 Type Script 的新手,使用 VSCode。 得到以下错误: 错误 TS2322:类型 '() => string' 不能分配给类型 'string'。 错误 TS2322:类型 '() => number' 不能分配给类型 'number'。 编码: DTO.ts interface DTO { getId(): number; getValue(): string; } export = DTO; 链接对象.ts class LinkedObject { public value: string = "Not Set"; public id: number = 0; constructor(value?: string, id?: number) { this.value = value; this.id = id; } } export = LinkedObject; 我正在尝试使用上述接口方法实例化LinkedObject类: TravelClientFormPopulator.ts class TravelClientFormPopulator { public populateComboBoxUsingDTOs(dataObjects: Array<DTO>, comboBoxID: string): void { // Get the
  • 角 2 | “{}”类型的指令参数不可分配给(Angular 2 | Directives Argument of type '{}' is not assignable to)
    问题 我是 Angular 2 的菜鸟。我在做 YouTube 教程,但每个教程都有directives:我被卡住的部分。 app.component.ts import { Component } from '@angular/core'; import { HeaderComponent } from './components/header/header.component' @Component({ selector: 'my-app', template: '<h1>Hello</h1><header></header>', directives: [HeaderComponent] }) export class AppComponent { } 错误输出是: Argument of type '{ selector: string; template: string; directives: typeof HeaderComponent[]; }' is not assignable to parameter of type 'ComponentMetadataType'.at line 6 col 3 header.component.ts import { Component } from '@angular/core'; @Component ({
  • 为什么此代码说“数字”类型不可分配给“从不”类型(Why is this code saying Type 'number' is not assignable to type 'never')
    问题 我试图创建一个称为一个字符串构建功能addToCache和函数的参数是通过接口来调用定义Payloads 因此,基于从名为MyStringsTest的enum注册的字符串的键代码,Typescript 应该使用该键代码执行类型查找。 export enum MyStringsTest { DEPART_IN_X_MINUTE='DEPART_IN_X_MINUTE', A_DRIVER_IS_ASKING_FOR='A_DRIVER_IS_ASKING_FOR', } export interface Payloads { [MyStringsTest.DEPART_IN_X_MINUTE]: number, [MyStringsTest.A_DRIVER_IS_ASKING_FOR]: string, } const cache:{ [K in keyof Payloads]?: (payload: Payloads[K]) => string } = {} function addToCache<K extends keyof Payloads>(code: K, cb: ((payload: Payloads[K]) => string)): void{ cache[code] = cb // I have the error here Type 'number' is
  • TypeScript + React.Lazy(TypeScript + React.Lazy)
    问题 const Game = React.lazy(() => new Promise( (resolve) => { setTimeout( () => resolve(import('./Game')) , 1000) })) 错误:错误:(6, 35) TS2345:'Promise<typeof import("D:/PROGECTS/SnakeReactReduxTS/snake-react-redux-ts/src/Components/Stages/Game")>' 类型的参数不可分配'{ 默认值:从不; } | PromiseLike<{ 默认值:从不; }> | 不明确的'。 类型 'Promise<typeof import("D:/PROGECTS/SnakeReactReduxTS/snake-react-redux-ts/src/Components/Stages/Game")>' 不可分配给类型 'PromiseLike<{ default: never; }>'。 'then' 的属性类型是不兼容的。 Type '<TResult1 = typeof import("D:/PROGECTS/SnakeReactReduxTS/snake-react-redux-ts/src/Components/Stages/Game"), TResult2 =
  • Angular 4/5 HttpClient:字符串类型的参数无法分配给“ body”(Angular 4/5 HttpClient: Argument of type string is not assignable to 'body')
    问题 Angular文档说: 响应主体不会返回您可能需要的所有数据。 有时服务器会返回特殊的标头或状态代码以指示某些条件,因此可能有必要进行检查。 为此,您可以告诉HttpClient您想要完整的响应,而不仅仅是带有watch选项的正文: http .get<MyJsonData>('/data.json', {observe: 'response'}) .subscribe(resp => { // Here, resp is of type HttpResponse<MyJsonData>. // You can inspect its headers: console.log(resp.headers.get('X-Custom-Header')); // And access the body directly, which is typed as MyJsonData as requested. console.log(resp.body.someField); }); 但是,当我尝试这样做时,我收到了编译时错误(尽管没有运行时错误,按预期方式工作): 错误TS2345:类型为'{headers的参数:HttpHeaders; observe: string;观察:字符串; }' is not assignable to parameter of type '{
  • “{header:Header;}”类型的参数不可分配给“RequestOptionsArgs”类型的参数(Argument of type '{header:Header;}' is not assignable to parameter of type 'RequestOptionsArgs')
    问题 我在尝试在 HTTP.POST/GET 请求中传递标头时出现以下错误Argument of type '{header:Header;}' is not assignable to parameter of type 'RequestOptionsArgs'. Property 'null' is missing in the type '{header:Header;}' Argument of type '{header:Header;}' is not assignable to parameter of type 'RequestOptionsArgs'. Property 'null' is missing in the type '{header:Header;}' 我尝试了很多解决方案,但没有锁定它。 这是我的代码: import { Injectable } from '@angular/core'; import { Response, RequestOptions, Headers, Http, URLSearchParams} from '@angular/http'; import { Observable, Subject } from 'rxjs/Rx'; import {Company} from './companyMaster'
  • 'MonoTypeOperatorFunction 类型的参数 ' 不能分配给类型为 'UnaryFunction 的参数(Argument of type 'MonoTypeOperatorFunction<any>' is not assignable to parameter of type 'UnaryFunction<Observable<any>, Observable<any>>')
    问题 我正在尝试从rxjs 5 迁移到 6,但我遇到了困难。 当我尝试这个时 this._connectivity.isOnline().pipe(first()).subscribe((state) => { this.syncCheck(user.uid); }); 我收到这个错误 Argument of type 'MonoTypeOperatorFunction<any>' is not assignable to parameter of type 'UnaryFunction<Observable<any>, Observable<any>>'. Types of parameters 'source' and 'source' are incompatible. Type 'import("/home/User/Desktop/projectname/node_modules/rxjs/Observable").Observable<any>' is not assignable to type 'import("/home/User/Desktop/projectname/node_modules/rxjs/internal/Observable").Observable<a...'. Property 'map' is missing in type
  • 同一类型参数的协方差和逆变(Covariance and Contravariance on the same type argument)
    问题 C# 规范声明一个参数类型不能同时是协变和逆变的。 这在创建协变或逆变接口时很明显,您分别用“out”或“in”装饰类型参数。 没有同时允许两者的选项(“outin”)。 这种限制仅仅是语言特定的约束,还是存在基于范畴论的更深层次、更基本的原因,使您不希望您的类型既是协变又是逆变? 编辑: 我的理解是数组实际上既是协变又是逆变的。 public class Pet{} public class Cat : Pet{} public class Siamese : Cat{} Cat[] cats = new Cat[10]; Pet[] pets = new Pet[10]; Siamese[] siameseCats = new Siamese[10]; //Cat array is covariant pets = cats; //Cat array is also contravariant since it accepts conversions from wider types cats = siameseCats; 回答1 正如其他人所说,泛型类型既是协变又是逆变在逻辑上是不一致的。 到目前为止,这里有一些很好的答案,但让我再补充两个。 首先,阅读我关于方差“有效性”主题的文章: http://blogs.msdn.com/b/ericlippert
  • 不可分配给“预期”类型的参数(is not assignable to parameter of type 'Expected<Promise<string>>' in editor)
    问题 我的测试是从命令行传递的,但是我使用Atom编辑typescript源。 当我在编辑器中打开其中一个测试文件时,我在这一行看到一个错误: expect(pageObject.name.getText()).toEqual('Some name'); 这是错误: Typescript Error Argument of type '"Some name"' is not assignable to parameter of type 'Expected<Promise<string>>'.at line 16 col 50 为什么这会显示在我的编辑器中? 然而测试通过了。 运行量角器测试的命令: protractor dist/protractor.config.js 来自package.json片段 "dependencies": { "typescript": "2.3.3" }, "devDependencies": { "@types/jasmine": "2.5.45", "@types/node": "^7.0.13", "jasmine-core": "^2.6.0", "jasmine-spec-reporter": "^4.1.0", "protractor": "^5.1.2" } tsconfig.fvt.test.json {
  • 为什么C和C ++编译器从不强制执行函数签名中的数组长度?(Why do C and C++ compilers allow array lengths in function signatures when they're never enforced?)
    问题 这是我在学习期间发现的: #include<iostream> using namespace std; int dis(char a[1]) { int length = strlen(a); char c = a[2]; return length; } int main() { char b[4] = "abc"; int c = dis(b); cout << c; return 0; } 因此,在变量int dis(char a[1]) , [1]似乎什么也不起作用,在全部,因为我可以使用a[2] 。 就像int a[]或char *a 。 我知道数组名称是一个指针以及如何传达一个数组,所以我的难题与这部分无关。 我想知道的是为什么编译器允许这种行为( int a[1] )。 还是它有我不知道的其他含义? 回答1 这是将数组传递给函数的语法的怪癖。 实际上,不可能在C中传递数组。如果编写的语法看起来像应该传递该数组,则实际发生的是改为传递了指向数组第一个元素的指针。 由于指针不包含任何长度信息,因此函数形式参数列表中[]的内容实际上会被忽略。 自从1970年代就做出了允许使用这种语法的决定,从那以后就引起了很多混乱。 回答2 第一维的长度被忽略,但是其他尺寸的长度对于允许编译器正确计算偏移量是必需的。 在下面的示例中,将向foo函数传递指向二维数组的指针。
  • 错误:类型“字符串”不可分配给类型“订阅”。 我该如何转换/解析这个?(Error: Type 'string' is not assignable to type 'Subscription'. How can I convert/parse this?)
    问题 我正在尝试使用 Observable 从我的数据库中获取一个简单的字符串。 我以前这样做过,没有任何问题。 配置是一个简单的对象,只有一个id: number和一个name: string 。 我从 ForkJoin 调用这个函数。 这是我的代码: private getMaxSeconds() { let maxSeconds = this.configurationRemoteService.get('MAX_SECONDS_VIDEOGRAMMETRY_SMALL') .subscribe(config => { maxSeconds = config.value; }, error => console.log(error)); return maxSeconds; } ForkJoin 代码(精简版): forkJoin([ this.getMaxSeconds(), ]).subscribe(response => { this.MaxSeconds= response[0] as string; }); 但这一次,我收到此错误: Type 'string' is not assignable to type 'Subscription'. 唯一的区别是现在我在函数中使用 let 声明变量。 如何将此Suscription转换或解析为string ? 我使用
  • TypeError:“ NoneType”类型的参数不可迭代(TypeError: argument of type 'NoneType' is not iterable)
    问题 我正在用Python做一个Hangman游戏。 在游戏中,一个python文件具有一种从数组中选择随机字符串并将其存储在变量中的功能。 然后将该变量传递给另一个文件中的函数。 该函数将用户的猜测作为字符串存储在变量中,然后检查该猜测是否在单词中。 但是,每当我输入字母并按Enter时,都会出现此问题标题中的错误。 请注意,我正在使用Python 2.7。 这是需要一个单词的函数的代码: import random easyWords = ["car", "dog", "apple", "door", "drum"] mediumWords = ["airplane", "monkey", "bananana", "window", "guitar"] hardWords = ["motorcycle", "chuckwalla", "strawberry", "insulation", "didgeridoo"] wordCount = [] #is called if the player chooses an easy game. #The words in the array it chooses are the shortest. #the following three functions are the ones that #choose the word
  • 字符串类型不可变的非技术优势(non-technical benefits of having string-type immutable)
    问题 我想知道从程序员的角度来看字符串类型不可变的好处。 技术优势(在编译器/语言方面)主要可以总结为如果类型是不可变的,则更容易进行优化。 阅读此处了解相关问题。 此外,在可变字符串类型中,要么您已经内置了线程安全(再说一次,优化更难做),要么您必须自己做。 在任何情况下,您都可以选择使用具有内置线程安全性的可变字符串类型,因此这并不是不可变字符串类型的真正优势。 (同样,进行处理和优化以确保不可变类型的线程安全会更容易,但这不是这里的重点。) 但是不可变字符串类型在使用中有什么好处呢? 让某些类型不可变而其他类型不可变有什么意义? 这对我来说似乎很不一致。 在 C++ 中,如果我想让一些字符串不可变,我会将它作为对函数的 const 引用传递( const std::string& )。 如果我想要原始字符串的可更改副本,我会将它作为std::string传递。 只有当我想让它可变时,我才将它作为参考( std::string& )传递。 所以我只能选择我想做什么。 我可以用所有可能的类型来做到这一点。 在 Python 或 Java 中,有些类型是不可变的(大部分都是原始类型和字符串),有些则不是。 在像 Haskell 这样的纯函数式语言中,一切都是不可变的。 是否有充分的理由说明这种不一致是有意义的? 还是纯粹出于技术层面的原因? 回答1
  • 为什么这段代码说“字符串”类型不可分配给“从不”类型(Why is this code saying Type 'string' is not assignable to type 'never')
    问题 为什么下面的代码说Type 'string' is not assignable to type 'never' ? 但是,编译后的 javascript 工作得很好 export enum MyStringsTest { DEPART_IN_X_MINUTE='DEPART_IN_X_MINUTE', A_DRIVER_IS_ASKING_FOR='A_DRIVER_IS_ASKING_FOR', } export interface Payloads { [MyStringsTest.DEPART_IN_X_MINUTE]: number, [MyStringsTest.A_DRIVER_IS_ASKING_FOR]: string, } type Cache = { [K in keyof Payloads]?: (payload: Payloads[K]) => string } const cache: Cache = {} function addToCache<K extends keyof Cache>(code: K, cb: (Cache[K])): void{ cache[code] = cb } addToCache(MyStringsTest.DEPART_IN_X_MINUTE, (data) => `Depart in ${data}