microsoft / microsoft/TypeScript

ClassDecorator type is inconsistent with Decorators proposal, needs type parameters

オープン
#53,790 コメント 7 件 リアクション 0 件 担当者 1 名 GitHub で見る

@rbuckton がすでに取り組んでいます。

2023年4月18日 から。

Needs Investigation
主要言語
Go
スター
111k
フォーク
14.4k
平均マージ
1日 19時間
マージ済み PR(30日)
117

説明

Bug Report

🔎 Search Terms

classdecorator
decorator context

🕗 Version & Regression Information
  • This is the behavior in every version I tried (version 5.0+), and I reviewed the FAQ for entries about decorators.
  • I was unable to test this on prior versions because proper ECMAScript decorators only became available in TypeScript 5.0.
⏯ Playground Link

Playground Link

💻 Code
class BaseClass {
}

const VoidClassDecorator = function(
    baseClass: typeof BaseClass,
    context: ClassDecoratorContext,
) : typeof BaseClass
{
    void(context);
    return baseClass;
}

@VoidClassDecorator
class UntypedDecorated extends BaseClass {

}

const TypedVoidClassDecorator: ClassDecorator = VoidClassDecorator;

@TypedVoidClassDecorator
class TypedDecorated extends BaseClass {
}
🙁 Actual behavior

Two errors:

Type '(baseClass: typeof BaseClass, context: ClassDecoratorContext<abstract new (...args: any) => any>) => typeof BaseClass' is not assignable to type 'ClassDecorator'.
  Target signature provides too few arguments. Expected 2 or more, but got 1.

Unable to resolve signature of class decorator when called as an expression.
  The runtime will invoke the decorator with 2 arguments, but the decorator expects 1.

The only difference between TypedVoidClassDecorator and VoidClassDecorator is the application of the ClassDecorator type, which doesn't take the context argument current ECMAScript decorators may use.

🙂 Expected behavior

No errors.

I would suggest a type taking three type parameters: the base class, a boolean flag for returning the original class type or returning void, and an arguments type which changes the return result.

import { Class } from "type-fest";

/* eslint-disable @typescript-eslint/no-explicit-any */
export type ClassDecoratorFunction<
  BaseClassType extends Class<unknown>,
  ReturnsModified extends boolean,
  Arguments extends any[] | false
> = 
    Arguments extends any[] ? 
    (...args: Arguments) => ClassDecoratorFunction<BaseClassType, ReturnsModified, false> :
    (
        baseClass: BaseClassType,
        context: ClassDecoratorContext,
    ) => (ReturnsModified extends true ? BaseClassType : void);

Playground Link, with fixes for earlier bugs

Update: fixing the above playground code!

This might require deprecating ye olde ClassDecorator type.

コントリビューションガイド

コントリビューションガイドを開く

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

評価

この issue はまだ評価されていません。

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。