Change decorator varargs to Generic variants

This commit is contained in:
Seth Posner 2023-04-19 17:49:15 -07:00
parent 7065de519f
commit 27d678a30b
11 changed files with 27 additions and 22 deletions

View file

@ -2,7 +2,7 @@ import { computed } from "@vue/reactivity";
import { isArray } from "@vue/shared"; import { isArray } from "@vue/shared";
import Select from "components/fields/Select.vue"; import Select from "components/fields/Select.vue";
import AchievementComponent from "features/achievements/Achievement.vue"; import AchievementComponent from "features/achievements/Achievement.vue";
import { Decorator } from "features/decorators/common"; import { Decorator, GenericDecorator } from "features/decorators/common";
import { import {
CoercableComponent, CoercableComponent,
Component, Component,
@ -139,7 +139,7 @@ export type GenericAchievement = Replace<
*/ */
export function createAchievement<T extends AchievementOptions>( export function createAchievement<T extends AchievementOptions>(
optionsFunc?: OptionsFunc<T, BaseAchievement, GenericAchievement>, optionsFunc?: OptionsFunc<T, BaseAchievement, GenericAchievement>,
...decorators: Decorator<T, BaseAchievement, GenericAchievement>[] ...decorators: GenericDecorator[]
): Achievement<T> { ): Achievement<T> {
const earned = persistent<boolean>(false, false); const earned = persistent<boolean>(false, false);
const decoratedData = decorators.reduce((current, next) => Object.assign(current, next.getPersistentData?.()), {}); const decoratedData = decorators.reduce((current, next) => Object.assign(current, next.getPersistentData?.()), {});

View file

@ -31,7 +31,7 @@ import { coerceComponent, isCoercableComponent, render } from "util/vue";
import { computed, Ref, ref, unref } from "vue"; import { computed, Ref, ref, unref } from "vue";
import { BarOptions, createBar, GenericBar } from "./bars/bar"; import { BarOptions, createBar, GenericBar } from "./bars/bar";
import { ClickableOptions } from "./clickables/clickable"; import { ClickableOptions } from "./clickables/clickable";
import { Decorator } from "./decorators/common"; import { Decorator, GenericDecorator } from "./decorators/common";
/** A symbol used to identify {@link Action} features. */ /** A symbol used to identify {@link Action} features. */
export const ActionType = Symbol("Action"); export const ActionType = Symbol("Action");
@ -104,7 +104,7 @@ export type GenericAction = Replace<
*/ */
export function createAction<T extends ActionOptions>( export function createAction<T extends ActionOptions>(
optionsFunc?: OptionsFunc<T, BaseAction, GenericAction>, optionsFunc?: OptionsFunc<T, BaseAction, GenericAction>,
...decorators: Decorator<T, BaseAction, GenericAction>[] ...decorators: GenericDecorator[]
): Action<T> { ): Action<T> {
const progress = persistent<DecimalSource>(0); const progress = persistent<DecimalSource>(0);
const decoratedData = decorators.reduce((current, next) => Object.assign(current, next.getPersistentData?.()), {}); const decoratedData = decorators.reduce((current, next) => Object.assign(current, next.getPersistentData?.()), {});

View file

@ -1,5 +1,5 @@
import BarComponent from "features/bars/Bar.vue"; import BarComponent from "features/bars/Bar.vue";
import { Decorator } from "features/decorators/common"; import { Decorator, GenericDecorator } from "features/decorators/common";
import type { import type {
CoercableComponent, CoercableComponent,
GenericComponent, GenericComponent,
@ -103,7 +103,7 @@ export type GenericBar = Replace<
*/ */
export function createBar<T extends BarOptions>( export function createBar<T extends BarOptions>(
optionsFunc: OptionsFunc<T, BaseBar, GenericBar>, optionsFunc: OptionsFunc<T, BaseBar, GenericBar>,
...decorators: Decorator<T, BaseBar, GenericBar>[] ...decorators: GenericDecorator[]
): Bar<T> { ): Bar<T> {
const decoratedData = decorators.reduce((current, next) => Object.assign(current, next.getPersistentData?.()), {}); const decoratedData = decorators.reduce((current, next) => Object.assign(current, next.getPersistentData?.()), {});
return createLazyProxy(feature => { return createLazyProxy(feature => {

View file

@ -1,7 +1,7 @@
import { isArray } from "@vue/shared"; import { isArray } from "@vue/shared";
import Toggle from "components/fields/Toggle.vue"; import Toggle from "components/fields/Toggle.vue";
import ChallengeComponent from "features/challenges/Challenge.vue"; import ChallengeComponent from "features/challenges/Challenge.vue";
import { Decorator } from "features/decorators/common"; import { Decorator, GenericDecorator } from "features/decorators/common";
import type { import type {
CoercableComponent, CoercableComponent,
GenericComponent, GenericComponent,
@ -150,7 +150,7 @@ export type GenericChallenge = Replace<
*/ */
export function createChallenge<T extends ChallengeOptions>( export function createChallenge<T extends ChallengeOptions>(
optionsFunc: OptionsFunc<T, BaseChallenge, GenericChallenge>, optionsFunc: OptionsFunc<T, BaseChallenge, GenericChallenge>,
...decorators: Decorator<T, BaseChallenge, GenericChallenge>[] ...decorators: GenericDecorator[]
): Challenge<T> { ): Challenge<T> {
const completions = persistent(0); const completions = persistent(0);
const active = persistent(false, false); const active = persistent(false, false);

View file

@ -1,5 +1,5 @@
import ClickableComponent from "features/clickables/Clickable.vue"; import ClickableComponent from "features/clickables/Clickable.vue";
import { Decorator } from "features/decorators/common"; import { Decorator, GenericDecorator } from "features/decorators/common";
import type { import type {
CoercableComponent, CoercableComponent,
GenericComponent, GenericComponent,
@ -97,7 +97,7 @@ export type GenericClickable = Replace<
*/ */
export function createClickable<T extends ClickableOptions>( export function createClickable<T extends ClickableOptions>(
optionsFunc?: OptionsFunc<T, BaseClickable, GenericClickable>, optionsFunc?: OptionsFunc<T, BaseClickable, GenericClickable>,
...decorators: Decorator<T, BaseClickable, GenericClickable>[] ...decorators: GenericDecorator[]
): Clickable<T> { ): Clickable<T> {
const decoratedData = decorators.reduce((current, next) => Object.assign(current, next.getPersistentData?.()), {}); const decoratedData = decorators.reduce((current, next) => Object.assign(current, next.getPersistentData?.()), {});
return createLazyProxy(feature => { return createLazyProxy(feature => {

View file

@ -15,7 +15,7 @@ import { convertComputable, processComputable } from "util/computed";
import { createLazyProxy } from "util/proxies"; import { createLazyProxy } from "util/proxies";
import type { Ref } from "vue"; import type { Ref } from "vue";
import { computed, unref } from "vue"; import { computed, unref } from "vue";
import { Decorator } from "./decorators/common"; import { GenericDecorator } from "./decorators/common";
/** An object that configures a {@link Conversion}. */ /** An object that configures a {@link Conversion}. */
export interface ConversionOptions { export interface ConversionOptions {
@ -125,7 +125,7 @@ export type GenericConversion = Replace<
*/ */
export function createConversion<T extends ConversionOptions>( export function createConversion<T extends ConversionOptions>(
optionsFunc: OptionsFunc<T, BaseConversion, GenericConversion>, optionsFunc: OptionsFunc<T, BaseConversion, GenericConversion>,
...decorators: Decorator<T, BaseConversion, GenericConversion>[] ...decorators: GenericDecorator[]
): Conversion<T> { ): Conversion<T> {
return createLazyProxy(feature => { return createLazyProxy(feature => {
const conversion = optionsFunc.call(feature, feature); const conversion = optionsFunc.call(feature, feature);

View file

@ -15,11 +15,13 @@ export interface BonusCompletionsFeatureOptions {
export interface BaseBonusAmountFeature { export interface BaseBonusAmountFeature {
amount: Ref<DecimalSource>; amount: Ref<DecimalSource>;
totalAmount: Ref<DecimalSource>; bonusAmount: ProcessedComputable<DecimalSource>;
totalAmount?: Ref<DecimalSource>;
} }
export interface BaseBonusCompletionsFeature { export interface BaseBonusCompletionsFeature {
completions: Ref<DecimalSource>; completions: Ref<DecimalSource>;
totalCompletions: Ref<DecimalSource>; bonusCompletions: ProcessedComputable<DecimalSource>;
totalCompletions?: Ref<DecimalSource>;
} }
export type BonusAmountFeature<T extends BonusAmountFeatureOptions> = Replace< export type BonusAmountFeature<T extends BonusAmountFeatureOptions> = Replace<
@ -47,6 +49,7 @@ export type GenericBonusCompletionsFeature = Replace<
/** /**
* Allows the addition of "bonus levels" to the decorated feature, with an accompanying "total amount". * Allows the addition of "bonus levels" to the decorated feature, with an accompanying "total amount".
* To function properly, the `createFeature()` function must have its generic type extended by {@linkcode BonusAmountFeatureOptions}. * To function properly, the `createFeature()` function must have its generic type extended by {@linkcode BonusAmountFeatureOptions}.
* Additionally, the base feature must have an `amount` property.
* To allow access to the decorated values outside the `createFeature()` function, the output type must be extended by {@linkcode GenericBonusAmountFeature}. * To allow access to the decorated values outside the `createFeature()` function, the output type must be extended by {@linkcode GenericBonusAmountFeature}.
* @example ```ts * @example ```ts
* createRepeatable<RepeatableOptions & BonusAmountFeatureOptions>(() => ({ * createRepeatable<RepeatableOptions & BonusAmountFeatureOptions>(() => ({

View file

@ -2,13 +2,15 @@ import { Replace, OptionsObject } from "../feature";
import { Computable, GetComputableType, processComputable, ProcessedComputable } from "util/computed"; import { Computable, GetComputableType, processComputable, ProcessedComputable } from "util/computed";
import { Persistent, State } from "game/persistence"; import { Persistent, State } from "game/persistence";
export type Decorator<FeatureOptions, BaseFeature = {}, GenericFeature = BaseFeature, S extends State = State> = { export type Decorator<FeatureOptions, BaseFeature = Object, GenericFeature = BaseFeature, S extends State = State> = {
getPersistentData?(): Record<string, Persistent<S>>; getPersistentData?(): Record<string, Persistent<S>>;
preConstruct?(feature: OptionsObject<FeatureOptions,BaseFeature,GenericFeature>): void; preConstruct?(feature: OptionsObject<FeatureOptions,BaseFeature,GenericFeature>): void;
postConstruct?(feature: OptionsObject<FeatureOptions,BaseFeature,GenericFeature>): void; postConstruct?(feature: OptionsObject<FeatureOptions,BaseFeature,GenericFeature>): void;
getGatheredProps?(feature: OptionsObject<FeatureOptions,BaseFeature,GenericFeature>): Partial<OptionsObject<FeatureOptions,BaseFeature,GenericFeature>> getGatheredProps?(feature: OptionsObject<FeatureOptions,BaseFeature,GenericFeature>): Partial<OptionsObject<FeatureOptions,BaseFeature,GenericFeature>>
} }
export type GenericDecorator = Decorator<unknown>;
export interface EffectFeatureOptions { export interface EffectFeatureOptions {
effect: Computable<any>; effect: Computable<any>;
} }
@ -33,7 +35,7 @@ export type GenericEffectFeature = Replace<
* }), effectDecorator) as GenericUpgrade & GenericEffectFeature; * }), effectDecorator) as GenericUpgrade & GenericEffectFeature;
* ``` * ```
*/ */
export const effectDecorator: Decorator<EffectFeatureOptions, {}, GenericEffectFeature> = { export const effectDecorator: Decorator<EffectFeatureOptions, unknown, GenericEffectFeature> = {
postConstruct(feature) { postConstruct(feature) {
processComputable(feature, "effect"); processComputable(feature, "effect");
} }

View file

@ -30,7 +30,7 @@ import { createLazyProxy } from "util/proxies";
import { coerceComponent, isCoercableComponent } from "util/vue"; import { coerceComponent, isCoercableComponent } from "util/vue";
import type { Ref } from "vue"; import type { Ref } from "vue";
import { computed, unref } from "vue"; import { computed, unref } from "vue";
import { Decorator } from "./decorators/common"; import { Decorator, GenericDecorator } from "./decorators/common";
/** A symbol used to identify {@link Repeatable} features. */ /** A symbol used to identify {@link Repeatable} features. */
export const RepeatableType = Symbol("Repeatable"); export const RepeatableType = Symbol("Repeatable");
@ -131,11 +131,11 @@ export type GenericRepeatable = Replace<
*/ */
export function createRepeatable<T extends RepeatableOptions>( export function createRepeatable<T extends RepeatableOptions>(
optionsFunc: OptionsFunc<T, BaseRepeatable, GenericRepeatable>, optionsFunc: OptionsFunc<T, BaseRepeatable, GenericRepeatable>,
...decorators: Decorator<T, BaseRepeatable, GenericRepeatable>[] ...decorators: GenericDecorator[]
): Repeatable<T> { ): Repeatable<T> {
const amount = persistent<DecimalSource>(0); const amount = persistent<DecimalSource>(0);
const decoratedData = decorators.reduce((current, next) => Object.assign(current, next.getPersistentData?.()), {}); const decoratedData = decorators.reduce((current, next) => Object.assign(current, next.getPersistentData?.()), {});
return createLazyProxy(feature => { return createLazyProxy<Repeatable<T>, Repeatable<T>>(feature => {
const repeatable = optionsFunc.call(feature, feature); const repeatable = optionsFunc.call(feature, feature);
repeatable.id = getUniqueID("repeatable-"); repeatable.id = getUniqueID("repeatable-");

View file

@ -1,4 +1,4 @@
import { Decorator } from "features/decorators/common"; import { Decorator, GenericDecorator } from "features/decorators/common";
import type { import type {
CoercableComponent, CoercableComponent,
GenericComponent, GenericComponent,
@ -103,7 +103,7 @@ export type GenericTreeNode = Replace<
*/ */
export function createTreeNode<T extends TreeNodeOptions>( export function createTreeNode<T extends TreeNodeOptions>(
optionsFunc?: OptionsFunc<T, BaseTreeNode, GenericTreeNode>, optionsFunc?: OptionsFunc<T, BaseTreeNode, GenericTreeNode>,
...decorators: Decorator<T, BaseTreeNode, GenericTreeNode>[] ...decorators: GenericDecorator[]
): TreeNode<T> { ): TreeNode<T> {
const decoratedData = decorators.reduce((current, next) => Object.assign(current, next.getPersistentData?.()), {}); const decoratedData = decorators.reduce((current, next) => Object.assign(current, next.getPersistentData?.()), {});
return createLazyProxy(feature => { return createLazyProxy(feature => {

View file

@ -119,7 +119,7 @@ export type GenericUpgrade = Replace<
*/ */
export function createUpgrade<T extends UpgradeOptions>( export function createUpgrade<T extends UpgradeOptions>(
optionsFunc: OptionsFunc<T, BaseUpgrade, GenericUpgrade>, optionsFunc: OptionsFunc<T, BaseUpgrade, GenericUpgrade>,
...decorators: Decorator<T, BaseUpgrade, GenericUpgrade>[] ...decorators: GenericDecorator[]
): Upgrade<T> { ): Upgrade<T> {
const bought = persistent<boolean>(false, false); const bought = persistent<boolean>(false, false);
const decoratedData = decorators.reduce((current, next) => Object.assign(current, next.getPersistentData?.()), {}); const decoratedData = decorators.reduce((current, next) => Object.assign(current, next.getPersistentData?.()), {});