diff --git a/apps/oxlint/fixtures/tsgolint/.oxlintrc.json b/apps/oxlint/fixtures/tsgolint/.oxlintrc.json index a43eea7c49462..b2d94d69ae346 100644 --- a/apps/oxlint/fixtures/tsgolint/.oxlintrc.json +++ b/apps/oxlint/fixtures/tsgolint/.oxlintrc.json @@ -24,6 +24,7 @@ "typescript/no-unnecessary-template-expression": "error", "typescript/no-unnecessary-type-arguments": "error", "typescript/no-unnecessary-type-assertion": "error", + "typescript/no-unnecessary-type-parameters": "error", "typescript/no-unsafe-argument": "error", "typescript/no-unsafe-assignment": "error", "typescript/no-unsafe-call": "error", diff --git a/apps/oxlint/fixtures/tsgolint/no-unnecessary-type-parameters.ts b/apps/oxlint/fixtures/tsgolint/no-unnecessary-type-parameters.ts new file mode 100644 index 0000000000000..65b2668789f34 --- /dev/null +++ b/apps/oxlint/fixtures/tsgolint/no-unnecessary-type-parameters.ts @@ -0,0 +1,5 @@ +// Examples of incorrect code for no-unnecessary-type-parameters rule + +function parseYAML(input: string): T { + return input as any as T; +} diff --git a/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware --silent@oxlint.snap b/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware --silent@oxlint.snap index cb237f13be374..7a2181927f342 100644 --- a/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware --silent@oxlint.snap +++ b/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware --silent@oxlint.snap @@ -6,8 +6,8 @@ arguments: --type-aware --silent working directory: fixtures/tsgolint ---------- -Found 0 warnings and 71 errors. -Finished in ms on 56 files with 55 rules using 1 threads. +Found 0 warnings and 74 errors. +Finished in ms on 57 files with 56 rules using 1 threads. ---------- CLI result: LintFoundErrors ---------- diff --git a/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware -c config-test.json@oxlint.snap b/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware -c config-test.json@oxlint.snap index 7338799d3bc24..3a5e8ff79e89e 100644 --- a/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware -c config-test.json@oxlint.snap +++ b/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware -c config-test.json@oxlint.snap @@ -40,7 +40,7 @@ working directory: fixtures/tsgolint help: Remove the debugger statement Found 2 warnings and 2 errors. -Finished in ms on 56 files with 1 rules using 1 threads. +Finished in ms on 57 files with 1 rules using 1 threads. ---------- CLI result: LintFoundErrors ---------- diff --git a/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware test.svelte@oxlint.snap b/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware test.svelte@oxlint.snap index 335ea1ac9b6a7..fa97d670c82fd 100644 --- a/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware test.svelte@oxlint.snap +++ b/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware test.svelte@oxlint.snap @@ -16,7 +16,7 @@ working directory: fixtures/tsgolint help: Remove the debugger statement Found 0 warnings and 1 error. -Finished in ms on 1 file with 55 rules using 1 threads. +Finished in ms on 1 file with 56 rules using 1 threads. ---------- CLI result: LintFoundErrors ---------- diff --git a/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware@oxlint.snap b/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware@oxlint.snap index b9d31669ffa9a..5035268d8bd57 100644 --- a/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware@oxlint.snap +++ b/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware@oxlint.snap @@ -197,6 +197,31 @@ working directory: fixtures/tsgolint 3 | `---- + x typescript-eslint(no-unnecessary-type-parameters): Type parameter T is used only once in the function signature. + ,-[no-unnecessary-type-parameters.ts:3:20] + 2 | + 3 | function parseYAML(input: string): T { + : ^ | + : | `-- This is the only usage of type parameter T in the signature. + 4 | return input as any as T; + `---- + + x typescript-eslint(no-unsafe-type-assertion): Unsafe assertion to `any` detected: consider using a more specific type to ensure safety. + ,-[no-unnecessary-type-parameters.ts:4:10] + 3 | function parseYAML(input: string): T { + 4 | return input as any as T; + : ^^^^^^^^^^^^ + 5 | } + `---- + + x typescript-eslint(no-unsafe-type-assertion): Unsafe assertion from `any` detected: consider using type guards or a safer assertion. + ,-[no-unnecessary-type-parameters.ts:4:10] + 3 | function parseYAML(input: string): T { + 4 | return input as any as T; + : ^^^^^^^^^^^^^^^^^ + 5 | } + `---- + x typescript-eslint(no-unsafe-argument): Unsafe argument of type any assigned to a parameter of type string. ,-[no-unsafe-argument.ts:3:13] 2 | function takesString(str: string): void {} @@ -564,8 +589,8 @@ working directory: fixtures/tsgolint `---- help: If your function does not access `this`, you can annotate it with `this: void`, or consider using an arrow function instead. -Found 0 warnings and 71 errors. -Finished in ms on 56 files with 55 rules using 1 threads. +Found 0 warnings and 74 errors. +Finished in ms on 57 files with 56 rules using 1 threads. ---------- CLI result: LintFoundErrors ---------- diff --git a/crates/oxc_linter/src/generated/rule_runner_impls.rs b/crates/oxc_linter/src/generated/rule_runner_impls.rs index 8d5c56d98db83..7c2f4b454c3fb 100644 --- a/crates/oxc_linter/src/generated/rule_runner_impls.rs +++ b/crates/oxc_linter/src/generated/rule_runner_impls.rs @@ -1732,6 +1732,13 @@ impl RuleRunner const RUN_FUNCTIONS: RuleRunFunctionsImplemented = RuleRunFunctionsImplemented::Run; } +impl RuleRunner + for crate::rules::typescript::no_unnecessary_type_parameters::NoUnnecessaryTypeParameters +{ + const NODE_TYPES: Option<&AstTypesBitset> = None; + const RUN_FUNCTIONS: RuleRunFunctionsImplemented = RuleRunFunctionsImplemented::Unknown; +} + impl RuleRunner for crate::rules::typescript::no_unsafe_argument::NoUnsafeArgument { const NODE_TYPES: Option<&AstTypesBitset> = None; const RUN_FUNCTIONS: RuleRunFunctionsImplemented = RuleRunFunctionsImplemented::Unknown; diff --git a/crates/oxc_linter/src/generated/rules_enum.rs b/crates/oxc_linter/src/generated/rules_enum.rs index b63aba34b9867..6d8b5be5a42b7 100644 --- a/crates/oxc_linter/src/generated/rules_enum.rs +++ b/crates/oxc_linter/src/generated/rules_enum.rs @@ -491,6 +491,7 @@ pub use crate::rules::typescript::no_unnecessary_template_expression::NoUnnecess pub use crate::rules::typescript::no_unnecessary_type_arguments::NoUnnecessaryTypeArguments as TypescriptNoUnnecessaryTypeArguments; pub use crate::rules::typescript::no_unnecessary_type_assertion::NoUnnecessaryTypeAssertion as TypescriptNoUnnecessaryTypeAssertion; pub use crate::rules::typescript::no_unnecessary_type_constraint::NoUnnecessaryTypeConstraint as TypescriptNoUnnecessaryTypeConstraint; +pub use crate::rules::typescript::no_unnecessary_type_parameters::NoUnnecessaryTypeParameters as TypescriptNoUnnecessaryTypeParameters; pub use crate::rules::typescript::no_unsafe_argument::NoUnsafeArgument as TypescriptNoUnsafeArgument; pub use crate::rules::typescript::no_unsafe_assignment::NoUnsafeAssignment as TypescriptNoUnsafeAssignment; pub use crate::rules::typescript::no_unsafe_call::NoUnsafeCall as TypescriptNoUnsafeCall; @@ -962,6 +963,7 @@ pub enum RuleEnum { TypescriptNoUnnecessaryTypeArguments(TypescriptNoUnnecessaryTypeArguments), TypescriptNoUnnecessaryTypeAssertion(TypescriptNoUnnecessaryTypeAssertion), TypescriptNoUnnecessaryTypeConstraint(TypescriptNoUnnecessaryTypeConstraint), + TypescriptNoUnnecessaryTypeParameters(TypescriptNoUnnecessaryTypeParameters), TypescriptNoUnsafeArgument(TypescriptNoUnsafeArgument), TypescriptNoUnsafeAssignment(TypescriptNoUnsafeAssignment), TypescriptNoUnsafeCall(TypescriptNoUnsafeCall), @@ -1676,8 +1678,10 @@ const TYPESCRIPT_NO_UNNECESSARY_TYPE_ASSERTION_ID: usize = TYPESCRIPT_NO_UNNECESSARY_TYPE_ARGUMENTS_ID + 1usize; const TYPESCRIPT_NO_UNNECESSARY_TYPE_CONSTRAINT_ID: usize = TYPESCRIPT_NO_UNNECESSARY_TYPE_ASSERTION_ID + 1usize; -const TYPESCRIPT_NO_UNSAFE_ARGUMENT_ID: usize = +const TYPESCRIPT_NO_UNNECESSARY_TYPE_PARAMETERS_ID: usize = TYPESCRIPT_NO_UNNECESSARY_TYPE_CONSTRAINT_ID + 1usize; +const TYPESCRIPT_NO_UNSAFE_ARGUMENT_ID: usize = + TYPESCRIPT_NO_UNNECESSARY_TYPE_PARAMETERS_ID + 1usize; const TYPESCRIPT_NO_UNSAFE_ASSIGNMENT_ID: usize = TYPESCRIPT_NO_UNSAFE_ARGUMENT_ID + 1usize; const TYPESCRIPT_NO_UNSAFE_CALL_ID: usize = TYPESCRIPT_NO_UNSAFE_ASSIGNMENT_ID + 1usize; const TYPESCRIPT_NO_UNSAFE_DECLARATION_MERGING_ID: usize = TYPESCRIPT_NO_UNSAFE_CALL_ID + 1usize; @@ -2463,6 +2467,9 @@ impl RuleEnum { Self::TypescriptNoUnnecessaryTypeConstraint(_) => { TYPESCRIPT_NO_UNNECESSARY_TYPE_CONSTRAINT_ID } + Self::TypescriptNoUnnecessaryTypeParameters(_) => { + TYPESCRIPT_NO_UNNECESSARY_TYPE_PARAMETERS_ID + } Self::TypescriptNoUnsafeArgument(_) => TYPESCRIPT_NO_UNSAFE_ARGUMENT_ID, Self::TypescriptNoUnsafeAssignment(_) => TYPESCRIPT_NO_UNSAFE_ASSIGNMENT_ID, Self::TypescriptNoUnsafeCall(_) => TYPESCRIPT_NO_UNSAFE_CALL_ID, @@ -3253,6 +3260,9 @@ impl RuleEnum { Self::TypescriptNoUnnecessaryTypeConstraint(_) => { TypescriptNoUnnecessaryTypeConstraint::NAME } + Self::TypescriptNoUnnecessaryTypeParameters(_) => { + TypescriptNoUnnecessaryTypeParameters::NAME + } Self::TypescriptNoUnsafeArgument(_) => TypescriptNoUnsafeArgument::NAME, Self::TypescriptNoUnsafeAssignment(_) => TypescriptNoUnsafeAssignment::NAME, Self::TypescriptNoUnsafeCall(_) => TypescriptNoUnsafeCall::NAME, @@ -4045,6 +4055,9 @@ impl RuleEnum { Self::TypescriptNoUnnecessaryTypeConstraint(_) => { TypescriptNoUnnecessaryTypeConstraint::CATEGORY } + Self::TypescriptNoUnnecessaryTypeParameters(_) => { + TypescriptNoUnnecessaryTypeParameters::CATEGORY + } Self::TypescriptNoUnsafeArgument(_) => TypescriptNoUnsafeArgument::CATEGORY, Self::TypescriptNoUnsafeAssignment(_) => TypescriptNoUnsafeAssignment::CATEGORY, Self::TypescriptNoUnsafeCall(_) => TypescriptNoUnsafeCall::CATEGORY, @@ -4860,6 +4873,9 @@ impl RuleEnum { Self::TypescriptNoUnnecessaryTypeConstraint(_) => { TypescriptNoUnnecessaryTypeConstraint::FIX } + Self::TypescriptNoUnnecessaryTypeParameters(_) => { + TypescriptNoUnnecessaryTypeParameters::FIX + } Self::TypescriptNoUnsafeArgument(_) => TypescriptNoUnsafeArgument::FIX, Self::TypescriptNoUnsafeAssignment(_) => TypescriptNoUnsafeAssignment::FIX, Self::TypescriptNoUnsafeCall(_) => TypescriptNoUnsafeCall::FIX, @@ -5687,6 +5703,9 @@ impl RuleEnum { Self::TypescriptNoUnnecessaryTypeConstraint(_) => { TypescriptNoUnnecessaryTypeConstraint::documentation() } + Self::TypescriptNoUnnecessaryTypeParameters(_) => { + TypescriptNoUnnecessaryTypeParameters::documentation() + } Self::TypescriptNoUnsafeArgument(_) => TypescriptNoUnsafeArgument::documentation(), Self::TypescriptNoUnsafeAssignment(_) => TypescriptNoUnsafeAssignment::documentation(), Self::TypescriptNoUnsafeCall(_) => TypescriptNoUnsafeCall::documentation(), @@ -7024,6 +7043,10 @@ impl RuleEnum { TypescriptNoUnnecessaryTypeConstraint::config_schema(generator) .or_else(|| TypescriptNoUnnecessaryTypeConstraint::schema(generator)) } + Self::TypescriptNoUnnecessaryTypeParameters(_) => { + TypescriptNoUnnecessaryTypeParameters::config_schema(generator) + .or_else(|| TypescriptNoUnnecessaryTypeParameters::schema(generator)) + } Self::TypescriptNoUnsafeArgument(_) => { TypescriptNoUnsafeArgument::config_schema(generator) .or_else(|| TypescriptNoUnsafeArgument::schema(generator)) @@ -8528,6 +8551,7 @@ impl RuleEnum { Self::TypescriptNoUnnecessaryTypeArguments(_) => "typescript", Self::TypescriptNoUnnecessaryTypeAssertion(_) => "typescript", Self::TypescriptNoUnnecessaryTypeConstraint(_) => "typescript", + Self::TypescriptNoUnnecessaryTypeParameters(_) => "typescript", Self::TypescriptNoUnsafeArgument(_) => "typescript", Self::TypescriptNoUnsafeAssignment(_) => "typescript", Self::TypescriptNoUnsafeCall(_) => "typescript", @@ -9779,6 +9803,11 @@ impl RuleEnum { TypescriptNoUnnecessaryTypeConstraint::from_configuration(value)?, )) } + Self::TypescriptNoUnnecessaryTypeParameters(_) => { + Ok(Self::TypescriptNoUnnecessaryTypeParameters( + TypescriptNoUnnecessaryTypeParameters::from_configuration(value)?, + )) + } Self::TypescriptNoUnsafeArgument(_) => Ok(Self::TypescriptNoUnsafeArgument( TypescriptNoUnsafeArgument::from_configuration(value)?, )), @@ -11423,6 +11452,7 @@ impl RuleEnum { Self::TypescriptNoUnnecessaryTypeArguments(rule) => rule.to_configuration(), Self::TypescriptNoUnnecessaryTypeAssertion(rule) => rule.to_configuration(), Self::TypescriptNoUnnecessaryTypeConstraint(rule) => rule.to_configuration(), + Self::TypescriptNoUnnecessaryTypeParameters(rule) => rule.to_configuration(), Self::TypescriptNoUnsafeArgument(rule) => rule.to_configuration(), Self::TypescriptNoUnsafeAssignment(rule) => rule.to_configuration(), Self::TypescriptNoUnsafeCall(rule) => rule.to_configuration(), @@ -12115,6 +12145,7 @@ impl RuleEnum { Self::TypescriptNoUnnecessaryTypeArguments(rule) => rule.run(node, ctx), Self::TypescriptNoUnnecessaryTypeAssertion(rule) => rule.run(node, ctx), Self::TypescriptNoUnnecessaryTypeConstraint(rule) => rule.run(node, ctx), + Self::TypescriptNoUnnecessaryTypeParameters(rule) => rule.run(node, ctx), Self::TypescriptNoUnsafeArgument(rule) => rule.run(node, ctx), Self::TypescriptNoUnsafeAssignment(rule) => rule.run(node, ctx), Self::TypescriptNoUnsafeCall(rule) => rule.run(node, ctx), @@ -12805,6 +12836,7 @@ impl RuleEnum { Self::TypescriptNoUnnecessaryTypeArguments(rule) => rule.run_once(ctx), Self::TypescriptNoUnnecessaryTypeAssertion(rule) => rule.run_once(ctx), Self::TypescriptNoUnnecessaryTypeConstraint(rule) => rule.run_once(ctx), + Self::TypescriptNoUnnecessaryTypeParameters(rule) => rule.run_once(ctx), Self::TypescriptNoUnsafeArgument(rule) => rule.run_once(ctx), Self::TypescriptNoUnsafeAssignment(rule) => rule.run_once(ctx), Self::TypescriptNoUnsafeCall(rule) => rule.run_once(ctx), @@ -13539,6 +13571,9 @@ impl RuleEnum { Self::TypescriptNoUnnecessaryTypeConstraint(rule) => { rule.run_on_jest_node(jest_node, ctx) } + Self::TypescriptNoUnnecessaryTypeParameters(rule) => { + rule.run_on_jest_node(jest_node, ctx) + } Self::TypescriptNoUnsafeArgument(rule) => rule.run_on_jest_node(jest_node, ctx), Self::TypescriptNoUnsafeAssignment(rule) => rule.run_on_jest_node(jest_node, ctx), Self::TypescriptNoUnsafeCall(rule) => rule.run_on_jest_node(jest_node, ctx), @@ -14279,6 +14314,7 @@ impl RuleEnum { Self::TypescriptNoUnnecessaryTypeArguments(rule) => rule.should_run(ctx), Self::TypescriptNoUnnecessaryTypeAssertion(rule) => rule.should_run(ctx), Self::TypescriptNoUnnecessaryTypeConstraint(rule) => rule.should_run(ctx), + Self::TypescriptNoUnnecessaryTypeParameters(rule) => rule.should_run(ctx), Self::TypescriptNoUnsafeArgument(rule) => rule.should_run(ctx), Self::TypescriptNoUnsafeAssignment(rule) => rule.should_run(ctx), Self::TypescriptNoUnsafeCall(rule) => rule.should_run(ctx), @@ -15055,6 +15091,9 @@ impl RuleEnum { Self::TypescriptNoUnnecessaryTypeConstraint(_) => { TypescriptNoUnnecessaryTypeConstraint::IS_TSGOLINT_RULE } + Self::TypescriptNoUnnecessaryTypeParameters(_) => { + TypescriptNoUnnecessaryTypeParameters::IS_TSGOLINT_RULE + } Self::TypescriptNoUnsafeArgument(_) => TypescriptNoUnsafeArgument::IS_TSGOLINT_RULE, Self::TypescriptNoUnsafeAssignment(_) => TypescriptNoUnsafeAssignment::IS_TSGOLINT_RULE, Self::TypescriptNoUnsafeCall(_) => TypescriptNoUnsafeCall::IS_TSGOLINT_RULE, @@ -16004,6 +16043,9 @@ impl RuleEnum { Self::TypescriptNoUnnecessaryTypeConstraint(_) => { TypescriptNoUnnecessaryTypeConstraint::HAS_CONFIG } + Self::TypescriptNoUnnecessaryTypeParameters(_) => { + TypescriptNoUnnecessaryTypeParameters::HAS_CONFIG + } Self::TypescriptNoUnsafeArgument(_) => TypescriptNoUnsafeArgument::HAS_CONFIG, Self::TypescriptNoUnsafeAssignment(_) => TypescriptNoUnsafeAssignment::HAS_CONFIG, Self::TypescriptNoUnsafeCall(_) => TypescriptNoUnsafeCall::HAS_CONFIG, @@ -16796,6 +16838,7 @@ impl RuleEnum { Self::TypescriptNoUnnecessaryTypeArguments(rule) => rule.types_info(), Self::TypescriptNoUnnecessaryTypeAssertion(rule) => rule.types_info(), Self::TypescriptNoUnnecessaryTypeConstraint(rule) => rule.types_info(), + Self::TypescriptNoUnnecessaryTypeParameters(rule) => rule.types_info(), Self::TypescriptNoUnsafeArgument(rule) => rule.types_info(), Self::TypescriptNoUnsafeAssignment(rule) => rule.types_info(), Self::TypescriptNoUnsafeCall(rule) => rule.types_info(), @@ -17486,6 +17529,7 @@ impl RuleEnum { Self::TypescriptNoUnnecessaryTypeArguments(rule) => rule.run_info(), Self::TypescriptNoUnnecessaryTypeAssertion(rule) => rule.run_info(), Self::TypescriptNoUnnecessaryTypeConstraint(rule) => rule.run_info(), + Self::TypescriptNoUnnecessaryTypeParameters(rule) => rule.run_info(), Self::TypescriptNoUnsafeArgument(rule) => rule.run_info(), Self::TypescriptNoUnsafeAssignment(rule) => rule.run_info(), Self::TypescriptNoUnsafeCall(rule) => rule.run_info(), @@ -18238,6 +18282,9 @@ pub static RULES: std::sync::LazyLock> = std::sync::LazyLock::new( RuleEnum::TypescriptNoUnnecessaryTypeConstraint( TypescriptNoUnnecessaryTypeConstraint::default(), ), + RuleEnum::TypescriptNoUnnecessaryTypeParameters( + TypescriptNoUnnecessaryTypeParameters::default(), + ), RuleEnum::TypescriptNoUnsafeArgument(TypescriptNoUnsafeArgument::default()), RuleEnum::TypescriptNoUnsafeAssignment(TypescriptNoUnsafeAssignment::default()), RuleEnum::TypescriptNoUnsafeCall(TypescriptNoUnsafeCall::default()), diff --git a/crates/oxc_linter/src/rules.rs b/crates/oxc_linter/src/rules.rs index f3c5de640956f..cf2514bae94d6 100644 --- a/crates/oxc_linter/src/rules.rs +++ b/crates/oxc_linter/src/rules.rs @@ -268,6 +268,7 @@ pub(crate) mod typescript { pub mod no_unnecessary_type_arguments; pub mod no_unnecessary_type_assertion; pub mod no_unnecessary_type_constraint; + pub mod no_unnecessary_type_parameters; pub mod no_unsafe_argument; pub mod no_unsafe_assignment; pub mod no_unsafe_call; diff --git a/crates/oxc_linter/src/rules/typescript/no_unnecessary_type_parameters.rs b/crates/oxc_linter/src/rules/typescript/no_unnecessary_type_parameters.rs new file mode 100644 index 0000000000000..ac5cdf4597a67 --- /dev/null +++ b/crates/oxc_linter/src/rules/typescript/no_unnecessary_type_parameters.rs @@ -0,0 +1,42 @@ +use oxc_macros::declare_oxc_lint; + +use crate::rule::Rule; + +#[derive(Debug, Default, Clone)] +pub struct NoUnnecessaryTypeParameters; + +declare_oxc_lint!( + /// ### What it does + /// + /// Disallow type parameters that are declared but not meaningfully used. + /// + /// ### Why is this bad? + /// + /// Unnecessary type parameters make signatures noisier and harder to understand, and they + /// often hide opportunities to simplify APIs. + /// + /// ### Examples + /// + /// Examples of **incorrect** code for this rule: + /// ```ts + /// function parseYAML(input: string): T { + /// return input as any as T; + /// } + /// ``` + /// + /// Examples of **correct** code for this rule: + /// ```ts + /// function parseYAML(input: string): unknown { + /// return input; + /// } + /// + /// function identity(value: T): T { + /// return value; + /// } + /// ``` + NoUnnecessaryTypeParameters(tsgolint), + typescript, + nursery, +); + +impl Rule for NoUnnecessaryTypeParameters {}