text:
TS2739: Type  is missing the following properties from type

TypeScript Version:  3.3.0-dev.201xxxxx

Search Terms:
Code
export const sp = '_@_';

export interface IWordsOutput
{
	_source?: any,

	s?: RegExp,
	r?: string | IRegExpCallback,

	flags?: string,
}

export interface IRegExpCallback
{
	($0: string, $1?: string, $2?: string, $3?: string, ...argv): string;
}

export interface IWords extends IWordsOutput
{
	[0]: string | RegExp,
	[1]: string | IRegExpCallback,
	[2]?: string,
}

export const words_source: IWords[] = [

	// this is work
	['HP', 'HP'],

	// Error:TS2739: Type 'string[]' is missing the following properties from type 'IWords': [0], [1]
	(function ()
	{
		let jobclass = '(?:A|B|C)';

		return [`${jobclass}${sp}${jobclass}`, '$1・$2'];
	})(),

];

Expected behavior:

no error

Actual behavior:

Error:TS2739: Type 'string[]' is missing the following properties from type 'IWords': [0], [1]

Playground Link:
Related Issues:

I think this might be #241?

I think this is just a matter of contextual types not propagating through IIFEs.

Hi,
I have the same error but slightly different scenario. I have a functional component wrapped with a redux connect function. Some props are provided via mapStateToProps. However, When calling a component without adding all the props gives me TS2739 error.
Sample code
button.tsx
export interface Props {
  canPost: boolean;
  postMethod: (name: string) => void;
  name: string;
}

const postButton = ({ canPost, postMethod, name }) => {
  const postSomething = () => {
    canPost && postMethod(name);
  };
  return <button  onClick={postSomething}>Do somthing</button>;
}

export default postButton;

canPost and postMethod are provided via connect function as follow:
index.ts
import { connect } from 'react-redux';
import postButton from  './button';
import { postMethod } from './store/actions';

export const mapStateToProps = (state) => {
  const { canPost } = state;
  return { canPost };
};
export const mapDispatchToProps = { postMethod };

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(postButton);

Then when i call the button component somewhere else, i only want to pass in the name as prop. Not anything else, however, i received TS2739: Type is missing the following properties from type for canPost and postMethod.
otherComponent.jsx
...in return function
 <postButton name="orders" />

For now i have to type canPost and postMethod as undefined. that will fixed the issue. But it is not actually undefined. Anyone could suggest me how to handle this properly? What's the best approach?
Many thanks in advance :)

I met this error in my project and worked around it by fixing the typescript version to '3.0' in package.json.

I've got a similar issue with the following code:
index.ts
import ListNode from './listNode';

const reverseKGroup:ListNode = (head: ListNode, k: number) => {
  const reversedNodes: ListNode[] = new ListNode[k];
    let current: ListNode = head;
    let index: number = k - 1;
    while (index > 0 /* && current.next != null */) {
      console.log('current=', current);
      reversedNodes[index] = current;
      current = current.next;
      //reversedNodes[index].next = current;
      index--;
    }
    for (let i: number = 0; i < reversedNodes.length; i++) console.log(`node(${i}): ${reversedNodes[i]}`);
    return reversedNodes[0];
}

export default reverseKGroup

listNode.ts
type LN = ListNode | null;

class ListNode {
  public val: number = -9999;
  public next: LN | undefined;
  public constructor(x: number, next: LN = null) {
    this.val = x;
    this.next = next;
  }

  public toString(): string {
    const fw: string = this.next != null ? '->' : '';
    return `${this.val}${fw}`;
  }
}

export default ListNode;

listNode.d.ts
declare type LN = ListNode | null;
declare class ListNode {
  public val: number;
  public next: LN | undefined;
  public constructor(x: number, next?: LN);
  public toString(): string;
}
export default ListNode;

@prakarangs, did you setup defaultProps for component 'clean' component?
Also, your component doesn't uses 'Props' interface at all.

@zmnv I did use props interface, just forgot to add the postButton = ({ canPost, postMethod, name }: Props) in sample code 🙈

Hi,
I have the same error but slightly different scenario. I have a functional component wrapped with a redux connect function. Some props are provided via mapStateToProps. However, When calling a component without adding all the props gives me TS2739 error.
Sample code
button.tsx
export interface Props {
  canPost: boolean;
  postMethod: (name: string) => void;
  name: string;
}

const postButton = ({ canPost, postMethod, name }) => {
  const postSomething = () => {
    canPost && postMethod(name);
  };
  return <button  onClick={postSomething}>Do somthing</button>;
}

export default postButton;

canPost and postMethod are provided via connect function as follow:
index.ts
import { connect } from 'react-redux';
import postButton from  './button';
import { postMethod } from './store/actions';

export const mapStateToProps = (state) => {
  const { canPost } = state;
  return { canPost };
};
export const mapDispatchToProps = { postMethod };

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(postButton);

Then when i call the button component somewhere else, i only want to pass in the name as prop. Not anything else, however, i received TS2739: Type is missing the following properties from type for canPost and postMethod.
otherComponent.tsx
...in return function
 <postButton name="orders" />

For now i have to type canPost and postMethod as undefined. that will fixed the issue. But it is not actually undefined. Anyone could suggest me how to handle this properly? What's the best approach?
Did you end up fixing this issue?

@weswigham agreed, this has more to do with IIFEs I think.

Hi,
I have the same error but slightly different scenario. I have a functional component wrapped with a redux connect function. Some props are provided via mapStateToProps. However, When calling a component without adding all the props gives me TS2739 error.
Sample code
button.tsx
export interface Props {
  canPost: boolean;
  postMethod: (name: string) => void;
  name: string;
}

const postButton = ({ canPost, postMethod, name }) => {
  const postSomething = () => {
    canPost && postMethod(name);
  };
  return <button  onClick={postSomething}>Do somthing</button>;
}

export default postButton;

canPost and postMethod are provided via connect function as follow:
index.ts
import { connect } from 'react-redux';
import postButton from  './button';
import { postMethod } from './store/actions';

export const mapStateToProps = (state) => {
  const { canPost } = state;
  return { canPost };
};
export const mapDispatchToProps = { postMethod };

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(postButton);

Then when i call the button component somewhere else, i only want to pass in the name as prop. Not anything else, however, i received TS2739: Type is missing the following properties from type for canPost and postMethod.
otherComponent.tsx
...in return function
 <postButton name="orders" />

For now i have to type canPost and postMethod as undefined. that will fixed the issue. But it is not actually undefined. Anyone could suggest me how to handle this properly? What's the best approach?
Many thanks in advance :)

I found this weird issue as well. The sub-component is complaining as the properties of it seem mandatory.
I managed to fix it with a workaround.
interface SubCompProps {
  dispatch: Dispatch;
  state: SpidersState;
}

const SubComp = (props: CompProps | any) => {
  if (!props) return <React.Fragment/>;
  const {dispatch, state} = props;
  ...
};

By adding CompProps | any and if (!props) return <React.Fragment/>; in the sub-component tsx file, the ts error disappeared.
<React.Fragment>
      <SubComp/>
</React.Fragment>

Through it seems not a trouble for now, it is still not the best solution. It will be awesome if some ts dev guru could fix it once for all.

authors: Berkmann18 DanielRosenwasser Jeff-Tian bluelovers iamtomhanks prakarangs tikazyq weswigham zmnv

repo: microsoft/TypeScript


text:
Type assertion breaks return type inference

TypeScript Version:  3.5.3

Search Terms: type assertion breaks return type inference, type assertions change type inference, incorrect return type inferred with type assertion
Code (note: edited after comment by @ajafff)
// having a type assertion breaks the infered return type
// expected return type: HTMLImageElement | HTMLPictureElement
// actual return type:   HTMLPictureElement
function test(foo: HTMLImageElement | HTMLPictureElement) {
    if (foo instanceof HTMLImageElement) {
        const bar = foo.cloneNode() as HTMLImageElement;
        return bar;
    }
    return foo;
}

Expected behavior: The type of the function is correctly inferred, with the asserted type being one of the members of the returned union type. (i.e. HTMLImageElement | HTMLPictureElement in the above example)
Actual behavior: The return type is incorrectly identified as only the asserted type.
Playground Link: Playground
Related Issues:

That's because Object is a supertype of string. This has nothing to do with type assertions or return type inference. Even if you explicitly declare the return type, it will still reduce to Object

Indeed - subtype reduction

@ajafff Is HTMLPictureElement also a supertype of HTMLImageElement? As you can see here, the same behavior is exhibited when using those.

According to MDN, HTMLPictureElement has no specific properties or methods over its superclass HTMLElement.  Therefore under structural typing HTMLPictureElement == HTMLElement which in turn is a supertype of HTMLImageElement.  Huh. 🤯

@fatcerberus Although it goes against everything my brain tells me, that does kinda make sense. A shame it isn't expressed in TypeScript in a less... confusing manner.

source: gharchive/issue

authors: ajafff birjolaxew fatcerberus

license_type: permissive

license_source: github-api


text:
Type instantiation is excessively deep with PartialRecursive & recursive list type

TypeScript Version:  3.7.2 (and nightly/next)
Search Terms:

Type instantiation is excessively deep and possibly infinite

Code
type Json =
    | string
    | number
    | boolean
    | null
    | { [property: string]: Json } // recursive  object doesn't cause any issues
    | Json[] // removing the list option resolves the issue

type PartialRecursive<T> = T extends object
    ? { [K in keyof T]?: PartialRecursive<T[K]> }
    : T

interface Data {
    value: Json
}

function acceptData(param: PartialRecursive<Data>) {}

const data = {} as Data
acceptData(data) // error TS2589: Type instantiation is excessively deep and possibly infinite.

Expected behavior:
Value field should be valid as both the type itself is already inferred as the Data type and the entire type is optional
Actual behavior:
The recursive list type causes an infinite (or excessive) calculation that fails.
Playground Link:

3.7.2
nightly
recursive list vs object

Related Issues:

https://github.com/microsoft/TypeScript/issues/34933
https://github.com/microsoft/TypeScript/issues/33132

Related: #33050, which introduced the ability to write type Json = ... | Json[] instead of requiring an  intervening interface like type Json = ... | JsonArray; interface JsonArray extends Array<Json> {}.

Looking at this some more I noticed that the problem is in my own (probably copied from somewhere) PartialRecursive type that doesn't handle Array types.
This fixes my case:
type PartialRecursive<T> = T extends object
    ? T extends Array<infer U> ? PartialRecursive<U>[]
    : { [K in keyof T]?: PartialRecursive<T[K]> }
    : T

I wouldn't be so quick to dismiss this; since TypeScript 3.1, mapped array/tuple types have been supported so you shouldn't have to special-case arrays like that.  Indeed, the pre-TS-3.7 way of typing Json does not have this problem with your original PartialRecursive:
type Json =
    | string
    | number
    | boolean
    | null
    | { [property: string]: Json }
    | JsonArray

interface JsonArray extends Array<Json> {}

type PartialRecursive<T> = T extends object
    ? { [K in keyof T]?: PartialRecursive<T[K]> }
    : T

interface Data {
    value: Json
}

function acceptData(param: PartialRecursive<Data>) {}

const data = {} as Data
acceptData(data) // no error

Playground link
So whatever's going on here isn't what I'd call a problem with recursive mapped types.  I don't know if this is a compiler bug / design limitation / working as intended, but I'm still interested in seeing what an official word here would be.

Re-opening, feel free to close if this works as expected

This is effectively a design limitation.
When a homomorphic mapped type is applied to an array type, we obtain the element type of the array and apply the mapped type's template type to that. This is done eagerly, which effectively causes a circularity when the type being mapped is itself circular.
As mentioned above, the original example works when an array case is added to the conditional type:
type PartialRecursive<T> =
    T extends (infer U)[] ? PartialRecursive<U>[] :
    T extends object ? { [K in keyof T]?: PartialRecursive<T[K]> } :
    T;

Here, PartialRecursive<U>[] is represented internally as a deferred type reference, and this saves us from the eager circularity problem. We could consider doing something similar for the case of applying a mapped type to an array type, but I don't think it is super important given that we have a very reasonable workaround.

authors: ahejlsberg idoros jcalz


text:
awaited operator is not added to the return types of async functions

TypeScript Version:  3.7.x-dev.201xxxxx

Search Terms:
Code
async function f<T>(a: T): Promise<T> {
    return a;
}
async function g<T>(a: T) {
    return a;
}
g(Promise.resolve(0));

Expected behavior:
Return type of f is invalid because the correct type is Promise<awaited T>.
Return types of g are Promise<awaited T> and Promise<number>.
Actual behavior:
Return type of f is valid although the correct type is Promise<awaited T>.
Return types of g are Promise<T> and Promise<Promise<number>>.
Playground Link: https://www.typescriptlang.org/play/index.html?ts=3.9.0-dev.20200324&ssl=1&ssc=1&pln=7&pc=23#code/IYZwngdgxgBAZgV2gFwJYHsLwDwBUB8AFMAFwy4CUZACgE7oC2qIApnvjAN4BQMfMtFsgS0swANzcAvt1CRYiFBiwBzdsTKUuvfoOGiYE6dxWE6jZiwB0gkOgA2ANxaEADBQrigA
Related Issues:

@rbuckton @amcasey @RyanCavanaugh @sandersn Since this bug would easily make wrong errors in user tests, this should be fixed soon.


text:
Promise rejection type.

Search Terms
Promise Reject Type

Suggestion

Add ability to type Promise rejections.
// Current Promise Constructor Implementation:
new <T>(executor: (resolve: (value?: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void): Promise<T>;

// Proposed Change:
new <T, E = any>(executor: (resolve: (value?: T | PromiseLike<T>) => void, reject: (reason?: E) => void) => void): Promise<T, E>;

Use Cases

When handling promise rejections, the type any isn't very useful. I would be useful to have the rejection have an actual type without the need to cast or type guard.
Examples

Promise.reject<never, string>('hello world')
  .catch(reason => {
    console.error(reason.length); // `reason` is of type string.
  });

class MyError extends Error {
  // ...
}

Promise.reject<never, MyError>(new MyError(/* ... */))
  .catch(reason => {
    // `reason` is of type MyError.
    const info = reason.getMoreInfo();
    // ...
  });

Checklist
My suggestion meets these guidelines:

[x] This wouldn't be a breaking change in existing TypeScript/JavaScript code
[x] This wouldn't change the runtime behavior of existing JavaScript code
[x] This could be implemented without emitting different JS based on the types of the expressions
[x] This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, etc.)
[x] This feature would agree with the rest of TypeScript's Design Goals.

Looks like duplicate of #6283 and other similar.
See for more details https://github.com/microsoft/TypeScript/issues/6283#issuecomment-240804072

I don't feel like they rejection type always has to be of type any/unknown.
It is obviously possible to detect what the rejection type is when Promise.reject is used. The hard bit would be detecting rejections caused by a throw statement inside an async function. But if we approach it from the perspective of a throw statement just being an alternative type of return statement, it seems possible to me (but probably quite difficult).
I've been having a bit of a play with this to see what it would be like add support. This is what I've got so far just by playing with type definitions.

p2                                         // p2 is of type Promise<number, string>
  .then((v2) =>  void cosnole.log(v2))     // v2 is of type number
  .catch((e2) => void console.error(e2));  // e2 is actually type string | ReferenceError, not string

Why would the type be string | ReferenceError? Isn't TypeScript already be reporting ReferenceError when they happen (2304)? (Or is that a strict mode only thing? If so then this proposal could just be for strict mode.)
playground

Yes, TS will report 2304 in this obvious case however emitted JS code will still have a change to receive both string and ReferenceError. Idea is to show that if there is something between resolve and catch - there are no guarantees that code between them wont throw something else (e.g. failed network request, incorrect normalize function etc.)
Looks like string will be only true for case p2.catch(...) but only if you believe that there are no other errors before resolve/reject.

Could you give a small example?
If myPromise.then(...).catch(...) can't be handled due to this but myPromise.catch(...) could be, imo that's still worth pursuing.

In unsound cases or unknown external code (e.g. computedBoolean) there is always a chance to have behavior that will throw
declare const computedBoolean: (params: any) => boolean; // but in general case might throw
const list = [{id: 111}, {id: 222}];

function firstThreeIds(data: Array<{id: number}>): number[] {
    return [
      data[0].id,
      data[1].id,
      data[2].id // no compile time error, but will throw
    ];
}

const p = new Promise<number[], string>((resolve, reject) => {
  if (computedBoolean(list)) { // can throw before resolve
    resolve(firstThreeIds(list)); // wil throw before resolve
  } else {
    reject("foo");
  }
});

p
  .catch((e) => { /* ... */}); // actually string | TypeError

So it looks like closest thing e can be typed is E | Error in definition (string | Error in current example).
And again if computedBoolean won't throw anything else (not sure which case will be encountered more often).

Could this proposal solve this issue?
https://github.com/microsoft/TypeScript/issues/39846

I just opened #45869.  I think maybe the best-case outcome would be implementing #13219 (throws-clause) and this issue, in which case it would become possible to document Promises that have a rejects type of never, i.e. rejection is not possible.  (Think return Promise.resolve(1);, etc.)
It would be a lot of work for most projects to migrate to throws-clause compliance but once done, the type checker would be able to reason about exception / rejection paths -- I would love to automate that reasoning, rather than getting bitten by orphaned async-function calls and having to hunt them down to fix on my own.

It's not. The rejection type is always unknown

Just encountered working with reason as an any type.  I understand why it doesn't have a specific type, but I guess I'm wondering why it's not instead typed as unknown?  There's a similar situation for the error property of ErrorEvent as it's completely non-standard.
In both situations, it seems that the appropriate type should be unknown, which by definition forces the developer into safe type guards.  Having it typed as any just takes TS out of the picture altogether.

Since this change isn't breaking you could always monkey patch the appropriate .d.ts file with the proposed change.  I think it would be nice if this made it into the official typings.  There still other changes that would need to be made to the compiler to get a good developer experience.  For instance, if you throw inside of a then() block, it would be nice if TS could infer that update the rejection type appropriately.  There was a ticket about adding support for tracking the exception types thrown by functions, but it was closed earlier this year, see https://github.com/microsoft/TypeScript/issues/13219#issuecomment-1515037604.  I'm guessing this proposal is dead-in-the-water for similar reasons.

I don't understand the argument that the rejection type can't be guaranteed.
Nothing can be guaranteed by typescript at runtime. Don't see why rejection type is different.
If I'm telling typescript rejection type is a certain type is because I'm supposed to know what I'm doing. Typescript code is usually full of castings assuming some stuff is defined, etc.. Don't see why this should be any different.

If you read the issues I linked from my previous post (2 years ago!), you'll see some of the reasoning. I think one of the most compelling arguments against allowing manual declaration of a throws or rejects type is that a novice who reads your code is unlikely to realize that you're making an unsafe assertion, along the lines of a typecast.
I'd still really like to see a way to annotate Promises that cannot reject, though. I actually write a lot of async functions with top level try/catch - it's a good pattern to follow when implementing an Express router callback, since the server library will not handle a rejection for you.

I think one of the most compelling arguments against allowing manual declaration of a throws or rejects type is that a novice who reads your code is unlikely to realize that you're making an unsafe assertion, along the lines of a typecast.

In this case is the developer that set the return type the one that needs to guaranteed the thrown exception is the correct type. I'm telling typescript I will only reject with that kind of type.
In typescript is perfectly valid to write
function sum(a: number, b: number): number {
  return 'hello world' and any as number;
}

This is totally valid TS although would fail at runtime, don't see why the developer could not explicitly tells typescript he will be make sure  the rejected value is a certain type. I'm not asking typescript to check thrown types etc. just so the consumers of the promises know the rejected type.

Sorry I wasn't more specific, but I wrote the previous comment from a phone.  I was referring to https://github.com/microsoft/TypeScript/issues/45869#issuecomment-920252246 :

it’s really not obvious that there is an assertion. Experienced TS developers are attuned to look out for unsoundness when they see as type assertions; this proposal makes the unsoundness very easy to overlook.

The point was that, if rejection-types were implemented, I could write
async function lookup(key: string): Promise<string, never> {
  try {
    return maybeGetValueEventually(key);
  } catch {
    logThatMightThrow(key);
    return "fallback";
  }
}

but without comprehensive checked exceptions (a feature that has already been rejected) the type-checker couldn't prove that the function never rejects.
In this example, the first generic argument in the returned-value Promise type (string) is type-checked -- if I wrote return 0 in the catch block instead of return "fallback", it would get flagged as an error -- but the second generic argument (never) is an unsafe assertion that I'm making.  There's no way for the typechecker to determine if the Promise never actually rejects, but there's no cast or as keyword to act as a red flag.  You'd need a pretty deep expertise in TypeScript to actually understand that difference.
I do think this could be handled by a linter rule ("all explicit Promise rejection types require a comment"), and I would still argue that some construct for asserting at its source that a Promise cannot reject is useful enough to merit a certain amount of novice-developer hazard, but I wanted to point out that there is a totally reasonable counterargument here.

authors: IllusionMH M-jerez RebeccaStevens kevinbarabash steverep thw0rted


text:
Add an overload to Object.fromEntries when called with const tuples

lib Update Request
Object.fromEntries as is declared today results in a loss of key names and a unionization of all values, or a complete loss of information and type of any.
This change would make it so that it is possible to create strict objects — from const tuples only.
Note that the usage of fromEntries with Arrays and non-readonly tuples cannot be made sound, so this issue only discusses the narrow case of const tuples.
Sample Code

const obj1 = Object.fromEntries([
  ['1', 2],
  ['3', 4],
] as const)
// this should result in an object of type: {1: 2, 3: 4}, but results instead in: { [k: string]: 2 | 4 }

const obj2 = Object.fromEntries([
  ['1', 2],
  ['3', '4'],
] as const)

// should result in an object of type: {1: 2, 3: '4'}, but results in: any

The how & example
This could be achieved by adding a new overload to Object.fromEntries in the case it is called with const tuples only.
This distinction is vital, because not distinguishing between Arrays, tuples and const tuples would make this change unsound. Only properties of a readonly tuple are guaranteed to be there at runtime, since they cannot be reassigned.
Here's a working proof-of-concept playground that should be sound in all cases, including the edge case of using a union type for the key.
The type is somewhat complex right now, so it would be great if we could somehow simplify it. Suggestions are welcome.
Related issues were previously closed, because the change would have been unsound without guarding for const tuples only (https://github.com/microsoft/TypeScript/issues/35745, https://github.com/microsoft/TypeScript/issues/49305, https://github.com/microsoft/TypeScript/issues/43332). Here however, the discussion is around const tuples only.
Configuration Check
My compilation target is es2022 and my lib is es2022.
Missing / Incorrect Definition

Object.fromEntries

Note
Opened by request of @sandersn in #50203.

Another failing test case
const x = fromEntries([] as [["foo", 1]] | Iterable<["bar", 2]>);

I really would rather avoid a conditional return type, at least not as the last overload. By supporting a reduced, but still improved, set of features I think this is better:
// Most generally useful
declare function fromEntries<T extends readonly [PropertyKey, unknown]>(
  entries: Iterable<T>
): { [P in T as P[0]]?: P[1] }

// Support wonky union types like `[["foo", 1]] | Iterable<["bar", 2]>`
declare function fromEntries<K extends PropertyKey, V>(
  entries: Iterable<readonly [K, V]>
): { [_ in K]?: V }

// For people destructuring `fromEntries`
declare function fromEntries(entries: Iterable<readonly [PropertyKey, unknown]>): { [key: PropertyKey]: unknown }

This is extremely clever, but far too complex to put into the standard library. Since this can merge in at the top of the overload list, you can still get the same behavior in userland with a custom additional lib file.

@RyanCavanaugh thanks for taking a look. I can make an NPM library for that, sounds like the way to go, unfortunately.
It would be possible to make this much simpler, if we had these two things built-in in TypeScript:

When doing a mapped type, ability to conditionally set optionality.
Right now, one can set the value using the X extends Y ? ... : ... pattern, but one cannot do it to add in or remove ? conditionally.
Perhaps a special type like +? or -? to add or remove optionality in mapped types, and similarly to add or remove readonly property +readonly could be added? E.g. { [K in keyof O]: O[K] extends X ? X & +? : X & -? }
Ability to refine based on negation. E.g. only const tuples: T extends readonly [...unknown] & not [...unknown]

@webstrand the failing test case you mentioned is failing for a good reason - there's no way to create a predictable object from that type, so it should be handled by another overload and fallback to a less strictly typed type. And as you notice, your simplified version unfortunately isn't sound. Believe me I've spent hours trying to figure it out.

Yes, please!

I've finally gotten around to publishing an NPM package with the strict Object.fromEntries typings.
See nesity-types.

Would it be OK to close this PR now?

authors: RyanCavanaugh alexweej niieani sandersn webstrand


text:
Infer from usage type logic

Bug Report

🔎 Search Terms

infer from usage
interface higher priority then type on type inference

🕗 Version & Regression Information
I think this has always been the behavior as far as I know. I didn't play around with this much yet, but the behavior exists in 4.0.5 and nightly and it seems odd for it to bounce around a lot.
⏯ Playground Link
playground link
💻 Code

// infers -> : { x: any; } = this makes sense
function inferWorksFine(obj) {
    return obj.x
}

// infers -> Z, this also makes sense
function inferFromFunctionCallTypedWithType(obj) {
    typedWithType(obj)
}
// infers -> Q, also makes sense
function inferFromFunctionCallTypedWithInterface(obj) {
    typedWithInterface(obj)
}

/*
 *  Here is when behavior gets odd
 *
 */

// infers -> { toplevel?: any; z?: number }
//      I would prefer if toplevel resovled to a non ? type but thats sorta stylistic
//      z is not optional and making it results in a type error
function inferFromUsageAndFunctionCallTypedWithType(obj) {
    typedWithType(obj)
    return obj.toplevel
}
// infers -> Q
//      This seems wrong to me, interface "types" have priority over
//      anonymous types, this results in errors because the inferred property
//      is an anonymous type
function inferFromUsageAndFunctionCallTypeWithInterface(obj) {
    typedWithInterface(obj)
    return obj.toplevel
}
// infers -> Q
//      From what I understand. The statement "type Z = {z: number}"
//      is a type alias Z to an anonymous type {z: number} so the interface
//      still has priority over it.
function inferFromFunctionCallTypedWithTypeAndFunctionCallTypedWithInterface(obj) {
    typedWithType(obj)
    typedWithInterface(obj)
}

// There are more examples you could contrive that look like this/combinations of this
// but I think this is enough for the point

type Z = {z: number}
function typedWithType(z: Z) {

}

interface Q {
    q: number
}
function typedWithInterface(q: Q) {}

🙁 Explanation of Actual behavior
Note: If I reference line numbers or any function I'm referring to the main branch I pulled I think yesterday.
So I sort of already discussed the behavior in the code itself. So I think it makes sense to talk about the code that causes this behavior.
So this file path "TypeScript/src/services/codefixes/inferFromUsage.ts" is where the logic for inferFromUsage lives afaik.
Just to do this in order:
// infers -> { toplevel?: any; z?: number }
//      I would prefer if toplevel resovled to a non ? type but thats sorta stylistic
//      z is not optional and making it results in a type error
function inferFromUsageAndFunctionCallTypedWithType(obj) {
    typedWithType(obj)
    return obj.toplevel
}

The reason these are optional seem to stem from the function combineAnonymousTypes
Specifically
const members = mapEntries(props, (name, types) => {
            const isOptional = types.length < anons.length ? SymbolFlags.Optional : 0;
            const s = checker.createSymbol(SymbolFlags.Property | isOptional, name as __String);
            s.links.type = checker.getUnionType(types);
            return [name, s];
        });

I'm actually not sure what the isOptional is intended to do. From what I understand anons.length is the number of anonymous types that the function is passed while types refers to possible type resolutions of the property with name name. I'm not sure what comparing these means.
Priority of interfaces
Since in the code I mention why I think type aliasing doesn't change anything I'll just show one example.
function inferFromFunctionCallTypedWithTypeAndFunctionCallTypedWithInterface(obj) {
    typedWithType(obj)
    typedWithInterface(obj)
}

So here the type will be resolved to the interface type. In the function combineTypes there is a priority table defined as follows:
const priorities: Priority[] = [
            {
                high: t => t === checker.getStringType() || t === checker.getNumberType(),
                low: t => t === stringNumber
            },
            {
                high: t => !(t.flags & (TypeFlags.Any | TypeFlags.Void)),
                low: t => !!(t.flags & (TypeFlags.Any | TypeFlags.Void))
            },
            {
                high: t => !(t.flags & (TypeFlags.Nullable | TypeFlags.Any | TypeFlags.Void)) && !(getObjectFlags(t) & ObjectFlags.Anonymous),
                low: t => !!(getObjectFlags(t) & ObjectFlags.Anonymous)
            }];

The last entry
{
                high: t => !(t.flags & (TypeFlags.Nullable | TypeFlags.Any | TypeFlags.Void)) && !(getObjectFlags(t) & ObjectFlags.Anonymous),
                low: t => !!(getObjectFlags(t) & ObjectFlags.Anonymous)
            }

gives high priority to non-anonymous types which I think only means interfaces or a type which at some point was mixed with an interface? This would take further investigation. I'm not sure the purpose of this behavior or if its a bug.
🙂 Expected behavior
I want the behavior to be that the generated types don't cause errors when they don't have to, since currently generated types don't satisfy what they need to be.
Deleting these two lines "solves" the behavior, but there are definitely more things to look into. I'm not sure why they were written - like I don't have any intuition on what problem they solve -  but I'm pretty sure they are there for important behavior.
Also since I'm listing things, I think this is the other "big one"
There are also more cases like
function f(obj) {
    g(obj)
    return obj.v > 1
}

not being able to resolve v to a number if "g" expects some type (even if the type is unrelated like {q}) and others.

The proposed changes sound good to me, assuming there aren't weird side effects. We can take a PR to see what happens under the suggested change.

Awesome! Thank you!
Putting this here mostly as a reminder to myself, but
interface A {
    a: number
}
interface B {
    b: number
}

function a(o: A) {}
function b(o: B) {}
// infers to B | A
function c(obj) {
    a(obj); b(obj)
}

while
type A = {
    a: number
}
type B = {
    b: number
}

function a(o: A) {}
function b(o: B) {}
// infers to {a?: number, b?: number}
function c(obj) {
    a(obj); b(obj)
}

This is also something I want to look into. I'm going to try to write some code to solve these problems. Would doing "npm run test" locally be the best way to make sure changes aren't breaking or is there something else I should do? Thank you!

authors: EliLichtblau RyanCavanaugh


text:
Can't write instantiation expression with function operand of lookup type from module import

Bug Report

🔎 Search Terms

typeof, import, function, generic, literal, syntax, error
🕗 Version & Regression Information

This is a crash

⏯ Playground Link

Playground link with relevant code
💻 Code

interface Arg<T = any, Params extends Record<string, any> = Record<string, any>> {
    "__is_argument__"?: true;
    meta?: T;
    params?: Params;
}

export function myFunction<T = any, U extends Record<string, any> = Record<string, any>>(arg: Arg<T, U>) { return (arg.params || {}) as U }

// @filename: file2.ts
// Approach 1
type FunctionType = typeof import('./input.js')['myFunction']<any, { slug: 'hello' }> // syntax error

// Approach 2
// type FT = typeof import('./input.js')['myFunction'] // FT should take in generics, but then we're back to approach 1
// type TypeTwo = FT<any, { slug: 'hi' }>

🙁 Behavior

FunctionType would be typed as (arg: Arg<any, { slug: 'hello'; }>) => { slug: 'hello'; }, but this can't be done due to syntax errors (starting with the generic arrows <).

@ahejlsberg what's the intended grammar here?

A typeof import(...) only permits member selection using dotted names (e.g. typeof import(...).x.y.z) and doesn't currently support specifying type arguments for an instantiation expression. We should probably lift the restriction on type arguments.
The repro above is parsed as:
type FunctionType = (typeof import('./input.js'))['myFunction']<any, { slug: 'hello' }>;

i.e. we end up with an indexed access type (typeof import('./input.js'))['myFunction'] and it isn't possible to apply type arguments to that (by design).
The repro really should be written:
type FunctionType = typeof import('./input.js').myFunction<any, { slug: 'hello' }>;

but then of course it falls victim to the lack of support for instantiation expression type arguments.

Thanks for the input - it may be my intellisense that shows exports when using indexed access types and not during dotted names.

We should probably lift the restriction on type arguments.

I do seem to require passing generics to functions like that (similar to the playground), so does this mean that this is planned? 🙂

@ineshbose I will have a PR up shortly that allows you to write
type FunctionType = typeof import('./input.js').myFunction<any, { slug: 'hello' }>;

I'm not seeing any issues with intellisense.

@ahejlsberg why is not possible to apply type arguments to an an indexed access type by design?
class Echo {
  echo = <T>(a: T): T => a;
}
type echoNum = Echo["echo"]<number>;

Is there any other way to achieve the same result as the (non working) previous snippet?

authors: RyanCavanaugh ahejlsberg darkbasic ineshbose


text:
Type 'VideoFrame' is not assignable to type 'Transferable'

Bug Report
Typescript does not let me Use VideoFrame as a transferable object when passing it to a webworker.
See #36823, its the same for 'OffscreenCanvas' (fixed)
🔎 Search Terms
VideoFrame, Transferable Objects Webcodecs
🕗 Version & Regression Information
Typescript Version 4.9.5
💻 Code
const video= document.createElement("video")
const videoFrame = new VideoFrame(video);
const worker = new Worker(URL.createObjectURL(new Blob([``],{type: "text/javascript"})))
worker.postMessage(videoFrame,[videoFrame])

🙁 Actual behavior
An error is thrown by the compiler:
Type 'VideoFrame' is not assignable to type 'Transferable'
🙂 Expected behavior
https://developer.mozilla.org/en-US/docs/Web/API/VideoFrame

VideoFrame is a transferable object.

It should not throw an error.

I'm not seeing an error in nightly. Seems like this has probably been fixed.

authors: RyanCavanaugh davidstrahm


text:
TS2322 error when using satisfies with strictFunctionTypes

🔎 Search Terms
satisfies strictFunctionTypes 2322
🕗 Version & Regression Information

This is the behavior in every version I tried, and I reviewed the FAQ for entries about strictFunctionTypes

⏯ Playground Link
https://www.typescriptlang.org/play?ts=5.3.0-dev.20230821#code/C4TwDgpgBAYgrgOwMYAUBOB7MBnKBeKAbwCgoyoAzDDALim2DQEsEBzAbmIF9jikMEDKACMAhmnxQAFIUrUoXOvGTos2AJT4AfFAAGVWlAAkhA112cKiJMCYCRogF4y5GBUuuqcm2WgjA4NAQ9AzoTMwsFXn5BYEpBSRJyKGAIBgBGOjE0ABpSclSGACYspzyuelFbbAomNKgAJQh+NAATAB4GZjYc6SkwTBw6JpaOrpZWXsQAawQMAHcELU08HXG2dS12IA
💻 Code
type FuncProps = {
    foo: string;
}

const bar = ({ foo }: FuncProps) => `foo: ${foo}`;
function baz({ foo }: FuncProps) { return `foo: ${foo}`; }

const fns = {
    test1: bar,
    test2: baz,
} satisfies Record<string, ((props: Record<string, unknown>) => string)>;

🙁 Actual behavior
Type '({ foo, bar, baz }: FuncProps) => string' is not assignable to type '(props: Record<string, unknown>) => string'.
Types of parameters '__0' and 'props' are incompatible.
Type 'Record<string, unknown>' is missing the following properties from type 'FuncProps': foo, bar, baz
🙂 Expected behavior
No error, I'm just using satisfies and type of __0 satisfies the one from props
Additional information about the issue
Using ((props: any) => string) "fixes" the error but is something I try to avoid

Type 'Record<string, unknown>' is missing the following properties from type 'FuncProps': foo, bar, baz

I don't see this error in your playground. Please make sure your described behavior matches the code you share.
Your issue can be simplified to:
type FuncProps = { foo: string; }

const bar = ({ foo }: FuncProps) => `foo: ${foo}`;

bar satisfies (props: Record<string, unknown>) => string;

You're asking "does my value match a function that can accept props with arbitrary amount of properties", but your value does not accept props with arbitrary amount of properties. Your props require at least the property foo, but Record<string, unknown> may very well omit this property. I see this working as intended.
You can either make your FuncProps an "empty" type by making all properties optional, or you check for FuncProps instead of Record<string, unknown>.

I don't see this error in your playground. Please make sure your described behavior matches the code you share.
Strange, I've just opened the playground and got the errors

Your issue can be simplified to:
type FuncProps = { foo: string; }

const bar = ({ foo }: FuncProps) => `foo: ${foo}`;

bar satisfies (props: Record<string, unknown>) => string;

👍

You're asking "does my value match a function that can accept props with arbitrary amount of properties", but your value does not accept props with arbitrary amount of properties. Your props require at least the property foo, but Record<string, unknown> may very well omit this property. I see this working as intended.
You can either make your FuncProps an "empty" type by making all properties optional, or you check for FuncProps instead of Record<string, unknown>.
I don't understand "satisfies" like that, especially when I'm able to use it the following way, but your explanation is logical.

const baz = {
    foo: "test"
} satisfies Record<string, unknown>;

Strange, I've just opened the playground and got the errors

The playground error is different. It does not mention "the following properties from type 'FuncProps': foo, bar, baz".

Strange, I've just opened the playground and got the errors

The playground error is different. It does not mention "the following properties from type 'FuncProps': foo, bar, baz".

Oh! I've simplified the test-case AFTER creating the issue and forgot to update the issue. Sorry about that

I don't understand "satisfies" like that, especially when I'm able to use it the following way

Think of it this way: Dog is assignable to Animal because a dog is an animal, right?  Anything you can do with any animal, you can do with a dog.  But (x: Dog) => void is not assignable to (x: Animal) => void because someone might call the function with a cat, but your implementation can only deal with dogs.
This is called contravariance and is what strictFunctionTypes enforces.

Think of it this way: Dog is assignable to Animal because a dog is an animal, right? Anything you can do with any animal, you can do with a dog. But (x: Dog) => void is not assignable to (x: Animal) => void because someone might call the function with a cat, but your implementation can only deal with dogs.
This is called contravariance and is what strictFunctionTypes enforces.

There seems (at least to me) to be a contradiction in that case, see for exemple  :
const baz = { foo: "test" };
baz satisfies Record<string, unknown>; // OK

type Baz = typeof baz;
const bar = (baz: Baz) => `foo: ${baz.foo}`;
bar satisfies (baz: Record<string, unknown>) => string; // Property 'foo' is missing in type 'Record<string, unknown>' but required in type 'Baz'.(1360)

So the type of baz satisfies Record<string, unknown> but when I use it as a function parameter it doesn't satisfies it anymore ??
Same thing if I explicitly use a type :
type Baz = { foo: string; }
const baz: Baz = { foo: "test" };
baz satisfies Record<string, unknown>; // OK

const bar = (baz: Baz) => `foo: ${baz.foo}`;
bar satisfies (baz: Record<string, unknown>) => string; // Property 'foo' is missing in type 'Record<string, unknown>' but required in type 'Baz'.(1360)

For me satisfies helps enforce some "lazy" or generic typing without loosing the more specific one implied by the code.
In my exemple it helps enforce baz is at least Record<string, unknown> but keep the more specific type ({ foo: "string" }, or if I've used const baz = { foo: "test" as const } ; { foo: "test" }
I want to be able to do the same with functions, i.e. make sure my functions are "at least" (_: Record<string, unknown>) => string but keep the better, more specific definition and I thought satisfies would allow me to do this and the documentation seemed to lean in my direction (but English isn't my mother tongue so I can misunderstand things a bit)
I'll read more on covariance and contravariance thanks for the pointer!

(baz: Record<string, unknown>) => string is a function which I can legally call, per its signature, as:
fun({ foo: 42 });

baz does not satisfy it, because it requires, per its signature, to be called with a { foo: "test" }.  That's contravariance :)

This is a correct error; @fatcerberus 's comment above correctly describes why

So how would you achieve what I'm trying to do ? i.e. ensure function signature respect at least a certain form without compromising final type ?

But that's not what you're trying to do

I'm pretty sure I know what I want to achieve ^^ I thought satisfies would do that but it seems I need something else.
Test case is reduced but in my case I have const structures where I want to enforce global form (i.e. error out on constructions outside of what I allow, specifically functions with multiple args or a first arg that isn't a Record) without overriding final type as does satisfies when no functions are involved

So what you're asking for, if I'm reading this right, is a way to say (using the animal analogy again):

"I want a function whose parameter is assignable to Animal, but the exact type of the parameter doesn't matter."

IMO it doesn't really make sense to specify a type this way, since it doesn't give you enough information to do anything with it.  You couldn't safely pass a random Animal to it, since it might require something specific (say, a Dog), but you also don't know exactly what kind of animal it wants.  Accordingly, there's no way to specify this type (well... strictFunctionTypes: false allows it, but it's unsound).

Using the animal analogy, I'm trying to say :
"I want a variable who satisfies following structure : a Record of functions with a unique parameter who extends Animal"
This will ensure that my variable, which has hundreds of entries, do not get functions that accept multiple parameters or that the first one is anything other than something that extend "Animal"
The trick is that satisfies don't change the final type, it just typecheck it, so the functions will know and tell exactly what specific parameter (say a Dog) they requires, and user of that structure too. But I've ensured that my structure is at least of a certain form.
Again this is what you can achieve with satisfies when you don't use functions :
type StringRecord = { [k: string]: StringRecord | string }

const records = {
  foo: "foo",
  bar: {
    bar: "bar",
    error: 0, // ts2322
  },
  baz: {
    baz: {
      baz: "baz"
      error: false,// ts2322
    }
    error: null,// ts2322
  }
  error: {},// ts2322
} satisfies StringRecord;

Here records final type is the one from its value but we typechecked it against StringRecord

satisfies following structure : a Record of functions with a unique parameter who extends Animal

Yeah, you can't do that with an assignability check (which is all that satisfies is), because assignability goes in the opposite direction for function parameters, hence contravariance.  afaik tcheck you want to do isn't possible in the current type system.

authors: KuSh MartinJohns RyanCavanaugh fatcerberus


text:
Array.isArray does not narrow return type of function

🔎 Search Terms
Array.isArray type narrowing
🕗 Version & Regression Information

This is the behavior in every version I tried, and I reviewed the FAQ for entries about type narrowing

⏯ Playground Link
https://www.typescriptlang.org/play?ts=5.4.0-dev.20240202#code/GYVwdgxgLglg9mABFATjAtgZVTMBzAeRQEEUUBDATwAoAoRRXABxCgC5EBnHfRAHy488AbQC6tAJQcolJgFM4wRmBZREcgB5Q5YACadBafGMQB+Q7hGjEHbkbyIA3vUZLqpCpQB0MTh6rUzKwSEk4uDChyUCAoSEFQXujkTNQGALwAfFxeOOjUIQDcLgC+LpHRscqqOWh5EkXFBUA
💻 Code
function trimStringOrArray(
  input: string | string[]
): typeof input extends string[] ? string[] : string {
  if (Array.isArray(input)) {
    return input.map(s => s.trim());
  }
  return input.trim();
};

🙁 Actual behavior
After checking the input whether it is an array, typescript expects the return type to be a string
🙂 Expected behavior
With the input being a string array, the function return type should also be a string array
Additional information about the issue
No response

As a note, this also does not work when using a generic type like this
function trimStringOrArray<I extends string | string[]>(
  input: I
): I extends string[] ? string[] : string {
  if (Array.isArray(input)) {
    return input.map(s => s.trim());
  }
  return input.trim();
};

The reason for this is that you're confusing type-space and value-space.
You have defined input: string | string[], so typeof input is equivalent to string | string[]. This type does not extend string[], so typeof input extends string[] ? string[] : string is equivalent to just string.
What you should do instead is use overloads:
function trimStringOrArray(input: string): string;
function trimStringOrArray(input: string[]): string[];
function trimStringOrArray(input: string | string[]): string | string[] {
   if (Array.isArray(input)) {
    return input.map(s => s.trim());
  }
  return input.trim();
}


text:
Declaration merging in plain JS with JSDoc

🔍 Search Terms
jsdoc declaration merging
✅ Viability Checklist

[X] This wouldn't be a breaking change in existing TypeScript/JavaScript code
[X] This wouldn't change the runtime behavior of existing JavaScript code
[X] This could be implemented without emitting different JS based on the types of the expressions
[X] This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
[X] This isn't a request to add a new utility type: https://github.com/microsoft/TypeScript/wiki/No-New-Utility-Types
[X] This feature would agree with the rest of our Design Goals: https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals

⭐ Suggestion
Ability to merge declarations.
📃 Motivating Example
For example, this is a declaration merge in TS:
export const Foo = makeFooClass()
export type Foo = InstanceType<typeof Foo>

In JS we can't do this. I was hoping for something similar to this to achieve the same:
export const Foo = makeFooClass() // returns a class
/** @export {InstanceType<typeof Foo>} Foo */

💻 Use Cases

What do you want to use this for? To merge declarations in certain cases.
What shortcomings exist with current approaches? There's no way to do it AFAICT
What workarounds are you using in the meantime? None

I don’t think that counts as a declaration merge, it’s just “declaring a type and a value with the same name”.  There’s no requirement that the two Foos be related as they exist in separate namespaces within the compiler.  Declaration merge is when e.g. you declare an interface more than once and the second one augments the first.

Maybe its named something else. If so, what is this pattern named where a single identifier carries both a type and a value? I could not find anything about it in the TS docs (maybe I don't know what to search for).

Maybe the syntax needs to be
/**
 * @export
 * @typedef {InstanceType<typeof Foo>} Foo
 */

Ah, @Gerrit0 pointed out that the following works because typedef is automatically exported:
export const Foo = makeFooClass() // returns a class
/** @typedef {InstanceType<typeof Foo>} Foo */

I do not see that this type exports feature is mentioned here:
https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html
Perhaps we need to add more info to that page.

If so, what is this pattern named where a single identifier carries both a type and a value? I could not find anything about it in the TS docs

I don't think there's a name for it because it's just declaring two different things that happen to have the same name, but the compiler considers them separate entities as one exists in type-space and the other in value-space[^1].  Nothing is really being merged.
[^1]: This split between type-space and value-space is why the typeof operator exists.  There's no requirement that Foo and typeof Foo be related, it's just in practice they usually are.

one exists in type-space and the other in value-space1. Nothing is really being merged.

They're being "merged" because the end user who will import the type can reference it with a single identifier, and to them it is the "same thing".
import {Foo} from './Foo.js'

const f = new Foo() // uses *both*, which to the user is a single thing.

authors: fatcerberus trusktr


text:
Add output file names api for supporting ts-loader

While working on TypeStrong/ts-loader#1003 i had to copy filename to output file names code to get outputs correctly. So exposing these as api seems like something useful.

@typescript-bot cherry-pick this into release-3.6

source: gharchive/pull-request


text:
Allow inlined-value usage of type-only const enums

Allow, e.g.
// @filename value-usage-of-type-only-const-enum.ts
import type { Direction } from "./direction";

const direction = Direction.Up;

if isolatedModules is false.
Motivation
eslint-plugin-import checks whether import statements are resolvable, so wants to know whether an import statement will be elided (by TypeScript) or not. Even if it could predict which imports were candidates for elision, that behavior is configurable (importsNotUsedAsValues), so the plugin takes the conservative view that all imports except type-only imports might or might not be elided.
This is a problem if type-only const enums can't be used as values:

User declares export const enum Direction { Up, Down, Left, Right } in direction.d.ts
If they don't type-only import { Direction } from "./direction", eslint-plugin-import warns that the import might not be resolvable (at runtime, assuming there's no direction.js to match direction.d.ts)
If they do type-only import it (it's a .d.ts without a .js, after all), TypeScript complains that it can't be used as a value (it's a type-only import, after all) https://github.com/import-js/eslint-plugin-import/issues/2267#issuecomment-952871674

The same problem as #40344.
I understand that type-only means type-only, and a type-only import on the right-hand side of an assignment looks really unexpected: https://github.com/microsoft/TypeScript/issues/36003#issuecomment-571265501
On the other hand going back to the motivation for type-only imports, my impression is that the whole deal was predictable import elision? https://github.com/microsoft/TypeScript/pull/35200
If isolatedModules is false:

Const enum values are compile-time only
Whether or not they're used as values, const enum imports are elided (good, because they can be declared in .d.ts -- what's there to import at runtime, if there's no .js?)

For these reasons, I'd like to allow value usage of type-only const enums if isolatedModules is false.
Before
isolatedModules false:
$ tsc value-usage-of-type-only-const-enum.ts
value-usage-of-type-only-const-enum.ts:3:19 - error TS1361: 'Direction' cannot be used as a value because it was imported using 'import type'.

3 const direction = Direction.Up;
                    ~~~~~~~~~

  value-usage-of-type-only-const-enum.ts:1:15
    1 import type { Direction } from "./direction";
                    ~~~~~~~~~
    'Direction' was imported here.

Found 1 error.

isolatedModules true:
$ tsc --isolatedModules value-usage-of-type-only-const-enum.ts
value-usage-of-type-only-const-enum.ts:3:19 - error TS1361: 'Direction' cannot be used as a value because it was imported using 'import type'.

3 const direction = Direction.Up;
                    ~~~~~~~~~

  value-usage-of-type-only-const-enum.ts:1:15
    1 import type { Direction } from "./direction";
                    ~~~~~~~~~
    'Direction' was imported here.

value-usage-of-type-only-const-enum.ts:3:19 - error TS2748: Cannot access ambient const enums when the '--isolatedModules' flag is provided.

3 const direction = Direction.Up;
                    ~~~~~~~~~

Found 2 errors.

After
isolatedModules false (error no more):
$ tsc value-usage-of-type-only-const-enum.ts

isolatedModules true (same as before):
$ tsc --isolatedModules value-usage-of-type-only-const-enum.ts
value-usage-of-type-only-const-enum.ts:3:19 - error TS1361: 'Direction' cannot be used as a value because it was imported using 'import type'.

3 const direction = Direction.Up;
                    ~~~~~~~~~

  value-usage-of-type-only-const-enum.ts:1:15
    1 import type { Direction } from "./direction";
                    ~~~~~~~~~
    'Direction' was imported here.

value-usage-of-type-only-const-enum.ts:3:19 - error TS2748: Cannot access ambient const enums when the '--isolatedModules' flag is provided.

3 const direction = Direction.Up;
                    ~~~~~~~~~

Found 2 errors.

Fixes #40344

@andrewbranch this PR is pretty small. From the issue discussion, it sounds like you'd be interested in a fix if it was simple. What do you think about this?

We’ve always known this change would be dead simple, but the issue is “Awaiting More Feedback.” The fairly low amount of feedback we’ve received on it has been positive, and I’ve been cautiously open to this change from the beginning. I think the downside is just adding to the confusion/complexity around what import type and isolatedModules each mean. I think we possibly need to have a broader conversation about the interaction between isolatedModules and const enums now that esbuild can inline them. If that becomes the norm for transpiling/minifying TS, then isolatedModules may be the wrong flag to toggle this behavior. At any rate, I don’t think I can unilaterally approve this PR.

I'm still stuck on, you e.g. import { AcBrowseToObjectType } from "activex-access" (pretend it's a module) with either importsNotUsedAsValues: "preserve" or preserveValueImports: true:

TS can't elide the import or named import because the runtime .js might have side effects (importsNotUsedAsValues) or you might subsequently have eval("console.log(AcBrowseToObjectType.acBrowseToForm)") (preserveValueImports),
but preserving the import/named import is problematic because there might not be any runtime .js or runtime named export.
Currently, if you explicitly elide the import (import type { AcBrowseToObjectType }) or named import (import { type AcBrowseToObjectType }) you get an error (which this PR suppresses) if you try to use its (inlined) value (unless you eval("AcBrowseToObjectType.acBrowseToForm") ... or // @ts-expect-error).

On the other hand I'm cool waiting for more feedback :+1:, in case a better solution can be found, or you can sidestep it entirely, or I'm missing the bigger picture, or there are developments on the horizon ...

If that becomes the norm for transpiling/minifying TS, then isolatedModules may be the wrong flag to toggle this behavior.

Instead of "if isolatedModules is false" I should have said "if inlined", whether by isolatedModules: false or, in future, some other condition. (I've edited the PR title accordingly.)

To help with PR housekeeping, I'm going to close this PR while it's still waiting on its bug to be accepted.

authors: andrewbranch jablko sandersn


text:
fix(47004): arguments detection for jsdoc / javascript has a false positive

Fixes #47004

@DanielRosenwasser I've added tests with checkJs. Also, I left the "fourslash" tests for "QI", if you think these tests are useless I will remove them.


text:
Add missing mapped type indexed access constraint

Fixes #47368.

@typescript-bot test this
@typescript-bot user test this
@typescript-bot run dt
@typescript-bot perf test this

So, one issue I'm seeing with the new constraint rules is this:
type ArgMap = { a: { x: number }, b: { y: string } };
type Func<K extends keyof ArgMap> = (x: ArgMap[K]) => void;
type Funcs = { [K in keyof ArgMap]: Func<K> };

function ff<K extends keyof ArgMap>(x: Funcs[K], y: Funcs[keyof ArgMap]) {
    x = y;  // Error
    y = x;  // Was ok, now errors
}

This is because for type Funcs[K] we used to explore the constraint Funcs[keyof ArgMap] where we now explore the constraints Func<K> and then Func<keyof ArgMap>. We may have to explore both possibilities.

Latest commits fix the issue I mentioned above. We know explore both possible constraints.

@typescript-bot perf test faster
@typescript-bot test this
@typescript-bot user test inline
@typescript-bot run dt

@typescript-bot user test this inline

@typescript-bot user test this

Tests and performance look good. I'm going to merge this.

authors: DanielRosenwasser ahejlsberg


text:
preserveValueImports + isolatedModules -> type-only ambient const enums

Currently, if you compile import Big, { RoundingMode } from "big.js" with preserveValueImports and isolatedModules the import name is preserved and you get at runtime:
import Big, { RoundingMode } from "big.js";
              ^^^^^^^^^^^^
SyntaxError: Named export 'RoundingMode' not found. The requested module 'big.js' is a CommonJS module, which may not support all module.exports as named exports.
CommonJS modules can always be imported via the default export, for example using:

import pkg from 'big.js';
const { RoundingMode } = pkg;

RoundingMode is an ambient const enum, defined in @types/big.js. There's no corresponding runtime value in big.js.
This PR extends the existing preserveValueImports + isolatedModules requirement, that imported types must be marked type-only, to ambient const enums.
If you add the type modifier (import Big, { type RoundingMode } from "big.js"), the compiler does remove the import name, solving the runtime error.
This PR specifically excludes non-ambient const enums, because they don't lead to runtime errors. (The import name is preserved, but the const enum is also preserved, so not an error at runtime.)

Possibly related to #46556 and #46626?
@jablko can you open an issue for discussion of this PR too? My initial reaction is that, in the PR you mentioned, the maintainers of @types/big.js acknowledged that RoundingMode was a mistake and would have removed it if the package were less depended on. I'm not sure changing the compiler is the right thing here.

@sandersn My rationale is:

A compile-time error would be better than a runtime one?
If isolatedModules is on, there's no difference to consumers between a type and an ambient const enum, so I think the proposed change to the predicate is correct?

I've opened https://github.com/microsoft/TypeScript/issues/48040 for this.
It's related to #46626 in that deconstified enums (whether via that PR or a build step) are independent of this PR, but that's not as important than the other deconstification reasons (JS consumers, single-file transpilation, compile-time vs. runtime version compatibility).
This PR deals with ambient const enums when isolatedModules is on vs. #46556 deals with const enums when they're inlined, i.e. off --- whether type-only const enums should act like single-file transpilation ambient const enums (no value usage --- the current behavior) vs. .d.ts const enums (inlined --- the proposed behavior).

authors: jablko sandersn


text:
in-proc ProjectQueryableSpace

https://learn.microsoft.com/en-us/visualstudio/extensibility/visualstudio.extensibility/project/project?view=vs-2022
On the above page is sample code for setting up in-proc Project query workspace as follows:
IProjectSystemQueryService queryService = await package.GetServiceAsync<IProjectSystemQueryService, IProjectSystemQueryService>();  ProjectQueryableSpace workSpace = queryService.QueryableSpace;
What is package?
I found the answer by ILSpying ProjectQueryAPIBrowser.dll.
Microsoft.VisualStudio.Shell.AsyncPackage package = (Microsoft.VisualStudio.Shell.AsyncPackage)(Object)this;.
I think the above statement should be added as the first line to the sample code above so there are no questions about package.

Hi @LeeMSilver
Thank you for bringing this to our attention, and we will update the documentation accordingly.
package in this case is an AsyncPackage, which represents a package for Visual Studio extension development.
More information on building an 'in-proc' extension can be found here: https://learn.microsoft.com/en-us/visualstudio/extensibility/visualstudio.extensibility/get-started/in-proc-extensions?view=vs-2022
Please let us know if you have any more questions!

Closing this issue. An update has been made to the documentation explaining package.

The new documentation now reads
"In the following code excerpt, package represents an instance of AsyncPackage, a class utilized in the development of Visual Studio extensions."
The problem is that AsyncPackage and an instance cannot be directly created. It is not documented how to create the class package.

authors: Jxwoon LeeMSilver

repo: microsoft/VSExtensibility

license: MIT