Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wrong definition of Array.find<T>() in lib.es2015.core.d.ts #38959

Closed
andreialecu opened this issue Jun 6, 2020 · 3 comments
Closed

Wrong definition of Array.find<T>() in lib.es2015.core.d.ts #38959

andreialecu opened this issue Jun 6, 2020 · 3 comments

Comments

@andreialecu
Copy link

TypeScript Version: 3.9.2

Search Terms: Array.find

Expected behavior:

See playground link and code below.

Array.find has an overload that takes a type parameter. I believe that supplying the type parameter should result in the value returned by .find<T>() to be typed as T.

Actual behavior:

Compilation error:

Argument of type '(this: void, t: AorB) => boolean' is not assignable to parameter of type '(this: void, value: AorB, index: number, obj: AorB[]) => value is B'.
  Signature '(this: void, t: AorB): boolean' must be a type predicate.(2345)

find is defined like this in lib.es2015.core.d.ts:

    find<S extends T>(predicate: (this: void, value: T, index: number, obj: T[]) => value is S, thisArg?: any): S | undefined;
    find(predicate: (value: T, index: number, obj: T[]) => unknown, thisArg?: any): T | undefined;

It seems that => value is S should be => unknown just like in the second overload.

The overload was added in #20385 (see https://github.com/microsoft/TypeScript/pull/20385/files#diff-aaa6939ec3d22a3cca5645eaac94d0beR33)

Related Issues:

Code

interface A {
    kind: "a";
    prop1: string;
}

interface B {
    kind: "b";
    prop2: string;

}

type AorB = A | B;

const foo: AorB[] = [];

const x = foo.find<B>(t => t.kind === "b" && t.prop2 === "foo");
Output
"use strict";
const foo = [];
const x = foo.find(t => t.kind === "b" && t.prop2 === "foo");
Compiler Options
{
  "compilerOptions": {
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "strictPropertyInitialization": true,
    "strictBindCallApply": true,
    "noImplicitThis": true,
    "noImplicitReturns": true,
    "useDefineForClassFields": false,
    "alwaysStrict": true,
    "allowUnreachableCode": false,
    "allowUnusedLabels": false,
    "downlevelIteration": false,
    "noEmitHelpers": false,
    "noLib": false,
    "noStrictGenericChecks": false,
    "noUnusedLocals": false,
    "noUnusedParameters": false,
    "esModuleInterop": true,
    "preserveConstEnums": false,
    "removeComments": false,
    "skipLibCheck": false,
    "checkJs": false,
    "allowJs": false,
    "declaration": true,
    "experimentalDecorators": false,
    "emitDecoratorMetadata": false,
    "target": "ES2017",
    "module": "ESNext"
  }
}

Playground Link: Provided

andreialecu added a commit to andreialecu/TypeScript that referenced this issue Jun 6, 2020
andreialecu added a commit to andreialecu/TypeScript that referenced this issue Jun 6, 2020
@andreialecu
Copy link
Author

Opened PR #38962

@MartinJohns
Copy link
Contributor

This is correct as it is. The point is to provide a type predicate (so a type guard function), to ensure that the found value matches the type. By changing it to unknown you defeat this purpose.

Given your example you could fix your code by changing the anonymous arrow function returning a boolean to a type guard function. You can do this either by adding a type annotation or moving it to a separate function:

foo.find<B>((t): t is B => t.kind === "b" && t.prop2 === "foo");

function isB(value: AorB): value is B { return value.kind === "b" && value.prop2 === "foo");
foo.find<B>(isB);

@andreialecu
Copy link
Author

Understood. Makes sense. Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants