mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-07-04 15:32:18 +02:00
Use InstanceType for proper narrowing
This commit is contained in:
parent
5f1a9f788f
commit
37af6d9c52
@ -14,21 +14,39 @@ export type * from "#app/data/moves/move";
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Map of move subclass names to their respective classes.
|
* Map of move subclass names to their respective classes.
|
||||||
|
* Does not include the ChargeMove subclasses. For that, use `ChargingMoveClassMap`.
|
||||||
|
*
|
||||||
|
* @privateremarks
|
||||||
|
* The `Never` field is necessary to ensure typescript does not improperly narrow a failed `is` guard to `never`.
|
||||||
|
*
|
||||||
|
* For example, if we did not have the never, and wrote
|
||||||
|
* ```
|
||||||
|
* function Foo(move: Move) {
|
||||||
|
* if (move.is("AttackMove")) {
|
||||||
|
*
|
||||||
|
* } else if (move.is("StatusMove")) { // typescript errors on the `is`, saying that `move` is `never`
|
||||||
|
*
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
*/
|
*/
|
||||||
export type MoveClassMap = {
|
export type MoveClassMap = {
|
||||||
AttackMove: typeof AttackMove;
|
AttackMove: AttackMove;
|
||||||
StatusMove: typeof StatusMove;
|
StatusMove: StatusMove;
|
||||||
SelfStatusMove: typeof SelfStatusMove;
|
SelfStatusMove: SelfStatusMove;
|
||||||
ChargingAttackMove: typeof ChargingAttackMove;
|
|
||||||
ChargingSelfStatusMove: typeof ChargingSelfStatusMove;
|
|
||||||
ChargeMove: typeof ChargingAttackMove | typeof ChargingSelfStatusMove;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Without the `Never: never` field, typescript will
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Union type of all move subclass names
|
* Union type of all move subclass names
|
||||||
*/
|
*/
|
||||||
export type MoveClass = keyof MoveClassMap;
|
export type MoveKindString = "AttackMove" | "StatusMove" | "SelfStatusMove";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map of move attribute names to attribute instances.
|
||||||
|
*/
|
||||||
export type MoveAttrMap = {
|
export type MoveAttrMap = {
|
||||||
[K in keyof MoveAttrConstructorMap]: InstanceType<MoveAttrConstructorMap[K]>;
|
[K in keyof MoveAttrConstructorMap]: InstanceType<MoveAttrConstructorMap[K]>;
|
||||||
};
|
};
|
||||||
|
@ -2527,17 +2527,11 @@ export class AllyStatMultiplierAbAttr extends AbAttr {
|
|||||||
* @extends AbAttr
|
* @extends AbAttr
|
||||||
*/
|
*/
|
||||||
export class ExecutedMoveAbAttr extends AbAttr {
|
export class ExecutedMoveAbAttr extends AbAttr {
|
||||||
canApplyExecutedMove(
|
canApplyExecutedMove(_pokemon: Pokemon, _simulated: boolean): boolean {
|
||||||
_pokemon: Pokemon,
|
|
||||||
_simulated: boolean,
|
|
||||||
): boolean {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
applyExecutedMove(
|
applyExecutedMove(_pokemon: Pokemon, _simulated: boolean): void {}
|
||||||
_pokemon: Pokemon,
|
|
||||||
_simulated: boolean,
|
|
||||||
): void {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2545,7 +2539,7 @@ export class ExecutedMoveAbAttr extends AbAttr {
|
|||||||
* @extends ExecutedMoveAbAttr
|
* @extends ExecutedMoveAbAttr
|
||||||
*/
|
*/
|
||||||
export class GorillaTacticsAbAttr extends ExecutedMoveAbAttr {
|
export class GorillaTacticsAbAttr extends ExecutedMoveAbAttr {
|
||||||
constructor(showAbility: boolean = false) {
|
constructor(showAbility = false) {
|
||||||
super(showAbility);
|
super(showAbility);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7773,7 +7767,7 @@ export function applyPreAttackAbAttrs(
|
|||||||
export function applyExecutedMoveAbAttrs(
|
export function applyExecutedMoveAbAttrs(
|
||||||
attrType: Constructor<ExecutedMoveAbAttr>,
|
attrType: Constructor<ExecutedMoveAbAttr>,
|
||||||
pokemon: Pokemon,
|
pokemon: Pokemon,
|
||||||
simulated: boolean = false,
|
simulated = false,
|
||||||
...args: any[]
|
...args: any[]
|
||||||
): void {
|
): void {
|
||||||
applyAbAttrsInternal<ExecutedMoveAbAttr>(
|
applyAbAttrsInternal<ExecutedMoveAbAttr>(
|
||||||
|
@ -446,8 +446,7 @@ export function initMoveAnim(move: MoveId): Promise<void> {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
moveAnims.set(move, null);
|
moveAnims.set(move, null);
|
||||||
const defaultMoveAnim =
|
const defaultMoveAnim = allMoves[move].is("AttackMove")
|
||||||
allMoves[move].is("AttackMove")
|
|
||||||
? MoveId.TACKLE
|
? MoveId.TACKLE
|
||||||
: allMoves[move].is("SelfStatusMove")
|
: allMoves[move].is("SelfStatusMove")
|
||||||
? MoveId.FOCUS_ENERGY
|
? MoveId.FOCUS_ENERGY
|
||||||
|
@ -123,7 +123,7 @@ import { MoveEffectTrigger } from "#enums/MoveEffectTrigger";
|
|||||||
import { MultiHitType } from "#enums/MultiHitType";
|
import { MultiHitType } from "#enums/MultiHitType";
|
||||||
import { invalidAssistMoves, invalidCopycatMoves, invalidMetronomeMoves, invalidMirrorMoveMoves, invalidSleepTalkMoves } from "./invalid-moves";
|
import { invalidAssistMoves, invalidCopycatMoves, invalidMetronomeMoves, invalidMirrorMoveMoves, invalidSleepTalkMoves } from "./invalid-moves";
|
||||||
import { SelectBiomePhase } from "#app/phases/select-biome-phase";
|
import { SelectBiomePhase } from "#app/phases/select-biome-phase";
|
||||||
import { ChargingMove, MoveAttrMap, MoveAttrString, MoveClass, MoveClassMap } from "#app/@types/move-types";
|
import { ChargingMove, MoveAttrMap, MoveAttrString, MoveKindString, MoveClassMap } from "#app/@types/move-types";
|
||||||
import { applyMoveAttrs } from "./apply-attrs";
|
import { applyMoveAttrs } from "./apply-attrs";
|
||||||
import { frenzyMissFunc, getMoveTargets } from "./move-utils";
|
import { frenzyMissFunc, getMoveTargets } from "./move-utils";
|
||||||
|
|
||||||
@ -153,10 +153,13 @@ export default abstract class Move implements Localizable {
|
|||||||
/**
|
/**
|
||||||
* Check if the move is of the given subclass without requiring `instanceof`.
|
* Check if the move is of the given subclass without requiring `instanceof`.
|
||||||
*
|
*
|
||||||
|
* ⚠️ Does _not_ work for {@linkcode ChargingAttackMove} and {@linkcode ChargingSelfStatusMove} subclasses. For those,
|
||||||
|
* use {@linkcode isChargingMove} instead.
|
||||||
|
*
|
||||||
* @param moveKind - The string name of the move to check against
|
* @param moveKind - The string name of the move to check against
|
||||||
* @returns Whether this move is of the provided type.
|
* @returns Whether this move is of the provided type.
|
||||||
*/
|
*/
|
||||||
public abstract is<K extends keyof MoveClassMap>(moveKind: K): this is MoveClassMap[K];
|
public abstract is<K extends MoveKindString>(moveKind: K): this is MoveClassMap[K];
|
||||||
|
|
||||||
constructor(id: MoveId, type: PokemonType, category: MoveCategory, defaultMoveTarget: MoveTarget, power: number, accuracy: number, pp: number, chance: number, priority: number, generation: number) {
|
constructor(id: MoveId, type: PokemonType, category: MoveCategory, defaultMoveTarget: MoveTarget, power: number, accuracy: number, pp: number, chance: number, priority: number, generation: number) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
@ -976,6 +979,10 @@ export default abstract class Move implements Localizable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class AttackMove extends Move {
|
export class AttackMove extends Move {
|
||||||
|
/** This field does not exist at runtime and must not be used.
|
||||||
|
* Its sole purpose is to ensure that typescript is able to properly narrow when the `is` method is called.
|
||||||
|
*/
|
||||||
|
declare private _: never;
|
||||||
override is<K extends keyof MoveClassMap>(moveKind: K): this is MoveClassMap[K] {
|
override is<K extends keyof MoveClassMap>(moveKind: K): this is MoveClassMap[K] {
|
||||||
return moveKind === "AttackMove";
|
return moveKind === "AttackMove";
|
||||||
}
|
}
|
||||||
@ -1026,21 +1033,29 @@ export class AttackMove extends Move {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class StatusMove extends Move {
|
export class StatusMove extends Move {
|
||||||
|
/** This field does not exist at runtime and must not be used.
|
||||||
|
* Its sole purpose is to ensure that typescript is able to properly narrow when the `is` method is called.
|
||||||
|
*/
|
||||||
|
declare private _: never;
|
||||||
constructor(id: MoveId, type: PokemonType, accuracy: number, pp: number, chance: number, priority: number, generation: number) {
|
constructor(id: MoveId, type: PokemonType, accuracy: number, pp: number, chance: number, priority: number, generation: number) {
|
||||||
super(id, type, MoveCategory.STATUS, MoveTarget.NEAR_OTHER, -1, accuracy, pp, chance, priority, generation);
|
super(id, type, MoveCategory.STATUS, MoveTarget.NEAR_OTHER, -1, accuracy, pp, chance, priority, generation);
|
||||||
}
|
}
|
||||||
|
|
||||||
override is<K extends keyof MoveClassMap>(moveKind: K): this is MoveClassMap[K] {
|
override is<K extends MoveKindString>(moveKind: K): this is MoveClassMap[K] {
|
||||||
return moveKind === "StatusMove";
|
return moveKind === "StatusMove";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SelfStatusMove extends Move {
|
export class SelfStatusMove extends Move {
|
||||||
|
/** This field does not exist at runtime and must not be used.
|
||||||
|
* Its sole purpose is to ensure that typescript is able to properly narrow when the `is` method is called.
|
||||||
|
*/
|
||||||
|
declare private _: never;
|
||||||
constructor(id: MoveId, type: PokemonType, accuracy: number, pp: number, chance: number, priority: number, generation: number) {
|
constructor(id: MoveId, type: PokemonType, accuracy: number, pp: number, chance: number, priority: number, generation: number) {
|
||||||
super(id, type, MoveCategory.STATUS, MoveTarget.USER, -1, accuracy, pp, chance, priority, generation);
|
super(id, type, MoveCategory.STATUS, MoveTarget.USER, -1, accuracy, pp, chance, priority, generation);
|
||||||
}
|
}
|
||||||
|
|
||||||
override is<K extends keyof MoveClassMap>(moveKind: K): this is MoveClassMap[K] {
|
override is<K extends MoveKindString>(moveKind: K): this is MoveClassMap[K] {
|
||||||
return moveKind === "SelfStatusMove";
|
return moveKind === "SelfStatusMove";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1067,11 +1082,6 @@ function ChargeMove<TBase extends SubMove>(Base: TBase, nameAppend: string) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
override is<K extends keyof MoveClassMap>(moveKind: K): this is MoveClassMap[K] {
|
|
||||||
// Anything subclassing this is a charge move.
|
|
||||||
return moveKind === "ChargeMove" || moveKind === nameAppend || super.is(moveKind);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the text to be displayed during this move's charging phase.
|
* Sets the text to be displayed during this move's charging phase.
|
||||||
* References to the user Pokemon should be written as "{USER}", and
|
* References to the user Pokemon should be written as "{USER}", and
|
||||||
@ -1151,14 +1161,14 @@ export abstract class MoveAttr {
|
|||||||
public selfTarget: boolean;
|
public selfTarget: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether this attribute is of the given type.
|
* Return whether this attribute is of the given type.
|
||||||
*
|
*
|
||||||
* @remarks
|
* @remarks
|
||||||
* Used to avoid requring the caller to have imported the specific attribute type, avoiding circular dependencies.
|
* Used to avoid requring the caller to have imported the specific attribute type, avoiding circular dependencies.
|
||||||
* @param attr - The attribute to check against
|
* @param attr - The attribute to check against
|
||||||
* @returns Whether the attribute is an instanceof the given type.
|
* @returns Whether the attribute is an instance of the given type.
|
||||||
*/
|
*/
|
||||||
public is<T extends MoveAttrString>(attr: T): this is MoveAttrConstructorMap[MoveAttrString] {
|
public is<T extends MoveAttrString>(attr: T): this is MoveAttrMap[T] {
|
||||||
const targetAttr = MoveAttrs[attr];
|
const targetAttr = MoveAttrs[attr];
|
||||||
if (!targetAttr) {
|
if (!targetAttr) {
|
||||||
return false;
|
return false;
|
||||||
@ -3096,7 +3106,11 @@ export class WeatherInstantChargeAttr extends InstantChargeAttr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class OverrideMoveEffectAttr extends MoveAttr {
|
export class OverrideMoveEffectAttr extends MoveAttr {
|
||||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
/** This field does not exist at runtime and must not be used.
|
||||||
|
* Its sole purpose is to ensure that typescript is able to properly narrow when the `is` method is called.
|
||||||
|
*/
|
||||||
|
declare private _: never;
|
||||||
|
override apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -8401,7 +8415,8 @@ const MoveAttrs = Object.freeze({
|
|||||||
ResistLastMoveTypeAttr,
|
ResistLastMoveTypeAttr,
|
||||||
ExposedMoveAttr,
|
ExposedMoveAttr,
|
||||||
});
|
});
|
||||||
/** Map of names */
|
|
||||||
|
/** Map of of move attribute names to their constructors */
|
||||||
export type MoveAttrConstructorMap = typeof MoveAttrs;
|
export type MoveAttrConstructorMap = typeof MoveAttrs;
|
||||||
|
|
||||||
export const selfStatLowerMoves: MoveId[] = [];
|
export const selfStatLowerMoves: MoveId[] = [];
|
||||||
|
@ -28,7 +28,6 @@ import {
|
|||||||
} from "#app/data/battler-tags";
|
} from "#app/data/battler-tags";
|
||||||
import { BattlerTagLapseType } from "#enums/battler-tag-lapse-type";
|
import { BattlerTagLapseType } from "#enums/battler-tag-lapse-type";
|
||||||
import type { MoveAttr } from "#app/data/moves/move";
|
import type { MoveAttr } from "#app/data/moves/move";
|
||||||
import { MoveEffectAttr } from "#app/data/moves/move";
|
|
||||||
import { getMoveTargets } from "#app/data/moves/move-utils";
|
import { getMoveTargets } from "#app/data/moves/move-utils";
|
||||||
import { applyFilteredMoveAttrs, applyMoveAttrs } from "#app/data/moves/apply-attrs";
|
import { applyFilteredMoveAttrs, applyMoveAttrs } from "#app/data/moves/apply-attrs";
|
||||||
import { MoveEffectTrigger } from "#enums/MoveEffectTrigger";
|
import { MoveEffectTrigger } from "#enums/MoveEffectTrigger";
|
||||||
@ -746,7 +745,7 @@ export class MoveEffectPhase extends PokemonPhase {
|
|||||||
): void {
|
): void {
|
||||||
applyFilteredMoveAttrs(
|
applyFilteredMoveAttrs(
|
||||||
(attr: MoveAttr) =>
|
(attr: MoveAttr) =>
|
||||||
attr instanceof MoveEffectAttr &&
|
attr.is("MoveEffectAttr") &&
|
||||||
attr.trigger === triggerType &&
|
attr.trigger === triggerType &&
|
||||||
(isNullOrUndefined(selfTarget) || attr.selfTarget === selfTarget) &&
|
(isNullOrUndefined(selfTarget) || attr.selfTarget === selfTarget) &&
|
||||||
(!attr.firstHitOnly || this.firstHit) &&
|
(!attr.firstHitOnly || this.firstHit) &&
|
||||||
|
Loading…
Reference in New Issue
Block a user