Skip to content

in operator typeguard precision loss #51339

New issue

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

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

Already on GitHub? # to your account

Open
santa-trout opened this issue Oct 28, 2022 · 2 comments
Open

in operator typeguard precision loss #51339

santa-trout opened this issue Oct 28, 2022 · 2 comments
Labels
Experience Enhancement Noncontroversial enhancements Help Wanted You can do this Suggestion An idea for TypeScript

Comments

@santa-trout
Copy link

santa-trout commented Oct 28, 2022

Bug Report

πŸ”Ž Search Terms

πŸ•— Version & Regression Information

v4.9.0 v4.9.1 5.0.0-dev.20221101

⏯ Playground Link

Playground link with relevant code

πŸ’» Code

function addressOrThrow(value: unknown) {
  if (typeof value !== "object" || value == null) throw new TypeError();

  if (!("street" in value) || typeof value.street !== "string")
    throw new TypeError();

  if (!("houseNumber" in value) || typeof value.houseNumber !== "number")
    throw new TypeError();

  return value;
}

function addressOrThrowTG(value: unknown): value is Address {
  addressOrThrow(value);
  return true;
}

function personOrThrow(value: unknown) {
  if (typeof value !== "object" || value == null) throw new TypeError();

  if (!("firstName" in value) || typeof value.firstName !== "string")
    throw new TypeError();

  if (!("lastName" in value) || typeof value.lastName !== "string")
    throw new TypeError();

  if ("middleName" in value && typeof value.middleName !== "string")
    throw new TypeError();

  if (!("addresses" in value) || !Array.isArray(value.addresses))
    throw new TypeError();

  if (!value.addresses.every(addressOrThrowTG))
    throw new TypeError();

  return value;
}

type Address = ReturnType<typeof addressOrThrow>;

type Person = ReturnType<typeof personOrThrow>;

πŸ™ Actual behavior

type Address = object & Record<"street", unknown> & Record<"houseNumber", unknown>
type Person = object & Record<"firstName", unknown> & Record<"lastName", unknown> & Record<"addresses", unknown>

πŸ™‚ Expected behavior

type Address = object & Record<"street", string> & Record<"houseNumber", number>
type Person = object & Record<"firstName", string> & Partial<Record<"middleName", string>> & Record<"lastName", string> & Record<"addresses", Address[]>

@RyanCavanaugh RyanCavanaugh added Suggestion An idea for TypeScript Help Wanted You can do this Experience Enhancement Noncontroversial enhancements labels Oct 28, 2022
@RyanCavanaugh
Copy link
Member

@ahejlsberg any easy way to make this happen?

@arahansen
Copy link

Also just ran into this. Here is a playground reproducing the issue.

The above errors in version 4.9.3 but no error in 4.8.4

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
Experience Enhancement Noncontroversial enhancements Help Wanted You can do this Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

3 participants