by

Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
  • 04:46
    typescript-bot synchronize #40156
  • 04:04
    00ff0000red edited #40644
  • 04:04
    00ff0000red edited #40644
  • 04:03
    00ff0000red edited #40644
  • 04:00
    00ff0000red opened #40644
  • 02:53
    agileago opened #40643
  • 02:08
    paboulos edited #40642
  • 02:05
    paboulos opened #40642
  • 01:05
    typescript-bot synchronize #40156
  • 00:12
    csigs synchronize #15575
  • 00:12
    csigs synchronize #28460
  • 00:12
    csigs synchronize #31641
  • 00:11

    csigs on hb_998_20200919001041455

    (compare)

  • 00:11
    typescript-bot labeled #40641
  • 00:11

    csigs on master

    LEGO: check in for master to te… LEGO: Merge pull request 40641 … (compare)

  • 00:11
    csigs closed #40641
  • 00:11
    csigs opened #40641
  • 00:11

    csigs on hb_998_20200919001041455

    LEGO: check in for master to te… (compare)

  • 00:06
    mjbvz edited #40640
  • 00:06
    mjbvz opened #40640
Salathiel Genèse
@SalathielGenese
I'm still alive, Keith. It won't change soon, eventually.
I hope you.re doing better.
habibaatify
@habibatify_twitter
interface Item {
    name: string;
    quantity?: number;
}

interface ItemConstructor {
    new( name: string, quantity: number): Item;
}

let itemConstructor: ItemConstructor = class {
    name!: string;
    constructor(name: string/**, quantity: number**/) {}
    //                      ^^^^^^^^^^^^^^^^^^^^^^^^
    // I expected an error because the required "quantity" parameter is missing
    // So this should not be assignable to itemConstructor...
    //
    // What am I missing
}
Keith Layne
@keithlayne

Here's a short example that shows basically the same concept:

type Foo = (a: string, b: number) => void;
const foo: Foo = (a) => {};

This is not an error. If you had a concrete class and passed too many args that would be an error, but in terms of function types, functions with fewer args are assignable. This is how JS works - if you pass too many args they are just ignored.

Aaron Beall
@aaronbeall

I know I've asked this before... is there a way to define a map type with specific keys? Like

type Foo = { a: string; b: string; c: string };
const config: Record<K extends keyof Foo, boolean> = {
  a: true,
  c: false
}
// typeof config = { a: boolean; c: boolean };

I know I can create a superfluous function to create the object with an inferred type

Aaron Beall
@aaronbeall

I came up with

const SubRecord = <K extends keyof any, T>() => 
  <SubK extends K>(obj: Record<SubK, T>) => 
    obj;

const config = SubRecord<keyof Foo, boolean>()({
  a: true,
  c: false
});

Is there a way that doesn't require a superfluous function?

webstrand
@webstrand
Nope, unfortunately.
If you put a type on the variable, the type of the variable will not be inferred from assignment even when the assignment is narrower
I use recast in my own build chain to remove stub functions.
But that's outside of typescript
webstrand
@webstrand
(It's just a simple rewrite from a const x = Narrow<{ a: string }>()({ a: "foo" } as const) to const x = { a: "foo" } after type checking is complete)
Reko Tiira
@rekotiira

This is a bit difficult to describe, but I have a bit of an issue and I'm not sure how to solve this, or is it even solvable in the first place. I have tried to make a simplified test-case..

I have a function test that takes 2 arguments, an object of type Wrapped<T> and a function that as argument takes type T. So basically something like:

type Fn<T> = (arg: T) => void;
declare const test: <T>(wrapped: Wrapped<T>, fn: Fn<T>) => void;

TS allows me to use test with an anonymous function and it infers the argument type nicely, eg, this works:

type Wrapped<T> = { value: T };
declare const foo: Wrapped<string>;
test(foo, (arg) => { /* ... */ }); // TS infers arg as string, which is what I want

Now let's say I instead have an union type inside the Wrapped Wrapped<string | undefined>. I then have a function that only takes a string as an argument. This will produce an error as expected:

declare const strFunc: (arg: string) => void;
declare const foo: Wrapped<string | undefined>;
test(foo, (arg) => strFunc(arg)); // ERROR: string | undefined is not assignable to string

But if I give strFunc directly as an argument to test without the anonymous function wrapping the call, then TS does not complain, i.e.:

declare const strFunc(arg: string);
declare const foo: Wrapped<string | undefined>;
test(foo, strFunc); // NO ERROR

I know the reason is because the strFunc has a narrower type than the Fn<string | undefined>, so it's assignable. But for my purposes I would like that case to give an error. I know I can fix it by inferring the inner type for the Wrapped from the function's parameter instead, but that breaks the usage of anonymous function, i.e.:

declare const test: <T extends (...args: any[]) => any>(
  wrapped: Wrapped<Parameters<T>[0]>,
  fn: T
) => void;
test(foo, strFunc); // ERROR: string | undefined is not assignable to string
test(foo, (arg) => strFunc(arg)); // inferring no longer works, arg is now any

So my question is, is there a way to make it so that both of these cases work at the same time? I've been banging my head to the wall for quite a while with this, but I haven't figured it out.

webstrand
@webstrand
@rekotiira This should do what you want:
export type NoInfer<T> = T & {[K in keyof T]: T[K]};
declare function test<T>(wrapped: Wrapped<T>, fn: (arg: NoInfer<T>) => void): void;
A bit more info about various NoInfer implementations: https://github.com/microsoft/TypeScript/issues/14829#issuecomment-520191642
Reko Tiira
@rekotiira

@webstrand that doesn't work. It'll just infer the type from the Wrapped<T>, which means T is inferred as string | undefined, which means the 2nd argument is going to be fn: (arg: NoInfer<string | undefined>) => void.

(arg: string) => void is assignable to (arg: NoInfer<string | undefined>) => void, so you won't get an error when you do test(foo, strFunc)

webstrand
@webstrand
@rekotiira I'm not clear on what's wrong, here's a demo which one one those the wrong?
Reko Tiira
@rekotiira
Hmm that's weird. I put that exact code in my VSCode and I'm not seeing an error.
webstrand
@webstrand
are you using strict?
Reko Tiira
@rekotiira
yep
webstrand
@webstrand
same version of tsc, or a different one?
Reko Tiira
@rekotiira
3.9.7
webstrand
@webstrand
huh
Does it catch the error when using tsc outside of vscode?
Reko Tiira
@rekotiira
let's try
still no error
hmm actually it seems that our tsconfig.json only has alwaysStrict set to true, but not strict
webstrand
@webstrand
ah "alwaysStrict" is just for added "use strict" to every file
Reko Tiira
@rekotiira
yeah seems so
webstrand
@webstrand
strict is the one that provides additional type safety
NoInfer doesn't work without strictNullChecks (which is implied by strict)
Reko Tiira
@rekotiira
seems like enabling produces quite a bit of errors in our project's codebase :D but I think it's probably going to be a good idea to go through these and fix them
webstrand
@webstrand
yeah, I really, really recommend using strict
Reko Tiira
@rekotiira
well strictNullChecks we actually do have set to true explicitly
could it be the strictFunctionTypes that does the magic?
webstrand
@webstrand
oh yeah, that's the one
Reko Tiira
@rekotiira
thanks a ton, this has been bugging me for days :laughing: should've come and ask about it earlier
I guess there's no way force that error without strict mode? This is library code, so would be nice if anyone using the library would get the error.
webstrand
@webstrand
Nope, it's one of the sad parts of Typescript that they've resisted enabling strict by default
And there's no way to force it from a library
Reko Tiira
@rekotiira
Well I'll take what I can get. If at least I can avoid people from making mistakes in our own project, that's better than nothing :)
Thanks again!
webstrand
@webstrand
most projects use strict, only legacy applications tend to have it disabled
Reko Tiira
@rekotiira
well that's good to hear at least
seems like in strict mode even without NoInfer it gives you an error. then the error is just for the wrapped type arg, while with NoInfer you get the error for the func arg, which is nicer
webstrand
@webstrand
Without strict function types, function arguments are considered "bivariant" more here
Reko Tiira
@rekotiira
@webstrand thanks for the information!
webstrand
@webstrand
I have some files *.script.ts in my code base that are executable scripts. Since they run in a different environement from the rest of my code, they can't share the project's tsconfig.json (which explicitly excludes **/*.script.ts).
vscode is reporting errors in those files due to ES2019 features, is there any way I can set another tsconfig file for .script.ts files?
Salathiel Genèse
@SalathielGenese

Hi everyone,

I have a package - @my/package
It comes with some predefined types.

Now, in @my/project, I linked to @my/package...
But I don't seem to be able to pick on those global types.

How should I go about it, please ?