diff --git a/src/data/abilities/ability.ts b/src/data/abilities/ability.ts index e883ab50ef9..014c80187bb 100644 --- a/src/data/abilities/ability.ts +++ b/src/data/abilities/ability.ts @@ -237,7 +237,15 @@ export interface AbAttrBaseParams { */ readonly simulated?: boolean; - /** Whether the ability is the passive ability. Default false */ + /** + * (For callers of `{@linkcode applyAbAttrs}`): If provided, **only** apply ability attributes of the passive (true) or active (false). + * + * This should almost always be left undefined, as otherwise it will *only* apply attributes of *either* the pokemon's passive (true) or + * non-passive (false) abilities. In almost all cases, you want to apply attributes that are from either. + * + * (For implementations of `AbAttr`): This will *never* be undefined, and will be `true` if the ability being applied + * is the pokemon's passive, and `false` otherwise. + */ passive?: boolean; } @@ -285,8 +293,8 @@ export abstract class AbAttr { */ apply(_params: AbAttrBaseParams): void {} - // The NoInfer in the next two signatures enforces that the type of the _params operand - // is always compatible with the type of apply. This allows fewer fields, but never a parameter with more. + // The `Exact` in the next two signatures enforces that the type of the _params operand + // is always compatible with the type of apply. This allows fewer fields, but never a type with more. getTriggerMessage(_params: Exact[0]>, _abilityName: string): string | null { return null; } diff --git a/src/data/abilities/apply-ab-attrs.ts b/src/data/abilities/apply-ab-attrs.ts index 2fc7a1f6cce..1571d64d170 100644 --- a/src/data/abilities/apply-ab-attrs.ts +++ b/src/data/abilities/apply-ab-attrs.ts @@ -23,15 +23,14 @@ function applySingleAbAttrs( return; } - // typescript assert for (const attr of ability.getAttrs(attrType)) { const condition = attr.getCondition(); let abShown = false; - if ( - (condition && !condition(pokemon)) || - // @ts-ignore: typescript can't unify the type of params with the generic type that was passed - !attr.canApply(params) - ) { + // We require an `as any` cast to suppress an error about the `params` type not being assignable to + // the type of the argument expected by `attr.canApply()`. This is OK, because we know that + // `attr` is an instance of the `attrType` class provided to the method, and typescript _will_ check + // that the `params` object has the correct properties for that class at the callsites. + if ((condition && !condition(pokemon)) || !attr.canApply(params as any)) { continue; } @@ -41,17 +40,16 @@ function applySingleAbAttrs( globalScene.phaseManager.queueAbilityDisplay(pokemon, passive, true); abShown = true; } - // @ts-expect-error - typescript can't unify the type of params with the generic type that was passed - const message = attr.getTriggerMessage(params, ability.name); + + const message = attr.getTriggerMessage(params as any, ability.name); if (message) { if (!simulated) { globalScene.phaseManager.queueMessage(message); } messages.push(message); } - - // @ts-ignore: typescript can't unify the type of params with the generic type that was passed - attr.apply(params); + // The `as any` cast here uses the same reasoning as above. + attr.apply(params as any); if (abShown) { globalScene.phaseManager.queueAbilityDisplay(pokemon, passive, false); @@ -84,10 +82,10 @@ function applyAbAttrsInternal( params.passive = passive; applySingleAbAttrs(attrType, params, gainedMidTurn, messages); globalScene.phaseManager.clearPhaseQueueSplice(); - // We need to restore passive to its original state in case it was undefined earlier - // this is necessary in case this method is called with an object that is reused. - params.passive = undefined; } + // We need to restore passive to its original state in the case that it was undefined on entry + // this is necessary in case this method is called with an object that is reused. + params.passive = undefined; } /**