From 94ebb321f11d3934e67fef40a40f14e546a13011 Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Thu, 29 Oct 2020 14:20:10 +0100 Subject: [PATCH] Complexity adjustments (#2803) * Complexity adjustments * cleanups * Small cleanups * Additional * revert era * ExtrinsicEra --- packages/api-derive/src/accounts/flags.ts | 61 +++++++++---------- packages/api-derive/src/accounts/info.ts | 44 +++++++------ packages/api-derive/src/democracy/util.ts | 11 +--- packages/api/src/checkTypes.manual.ts | 14 ++--- packages/api/test/util/SingleAccountSigner.ts | 10 +-- packages/rpc-provider/src/mock/index.ts | 30 ++++----- packages/types/src/codec/Option.ts | 6 +- packages/types/src/codec/Tuple.ts | 2 +- packages/types/src/create/createClass.ts | 4 +- packages/types/src/create/registry.ts | 4 +- packages/types/src/ethereum/LookupSource.ts | 24 ++++---- packages/types/src/extrinsic/ExtrinsicEra.ts | 10 +-- packages/types/src/generic/LookupSource.ts | 24 ++++---- packages/types/src/primitive/Data.ts | 2 +- .../types/src/primitive/DoNotConstruct.ts | 4 +- 15 files changed, 105 insertions(+), 145 deletions(-) diff --git a/packages/api-derive/src/accounts/flags.ts b/packages/api-derive/src/accounts/flags.ts index 11704622e7..02bca5b4db 100644 --- a/packages/api-derive/src/accounts/flags.ts +++ b/packages/api-derive/src/accounts/flags.ts @@ -20,9 +20,17 @@ type FlagsIntermediate = [ AccountId | undefined ]; -function isIncludedFn (accountId: AccountId | Address | string): (_: AccountId | Address |string) => boolean { - return function (id: AccountId | Address | string): boolean { - return id.toString() === accountId.toString(); +function parseFlags (address: AccountId | Address | string | null | undefined, [electionsMembers, councilMembers, technicalCommitteeMembers, societyMembers, sudoKey]: FlagsIntermediate): DeriveAccountFlags { + const isIncluded = (id: AccountId | Address | string) => + address + ? id.toString() === address.toString() + : false; + + return { + isCouncil: (electionsMembers?.map(([id]: ITuple<[AccountId, Balance]>) => id) || councilMembers || []).some(isIncluded), + isSociety: (societyMembers || []).some(isIncluded), + isSudo: sudoKey?.toString() === address?.toString(), + isTechCommittee: (technicalCommitteeMembers || []).some(isIncluded) }; } @@ -34,35 +42,24 @@ export function flags (instanceId: string, api: ApiInterfaceRx): (address?: Acco return memo(instanceId, (address?: AccountId | Address | string | null): Observable => { const councilSection = api.query.electionsPhragmen ? 'electionsPhragmen' : 'elections'; - return ( - combineLatest([ - address && api.query[councilSection]?.members - ? api.query[councilSection].members() - : of(undefined), - address && api.query.council?.members - ? api.query.council.members() - : of([]), - address && api.query.technicalCommittee?.members - ? api.query.technicalCommittee.members() - : of([]), - address && api.query.society?.members - ? api.query.society.members() - : of([]), - address && api.query.sudo?.key - ? api.query.sudo.key() - : of(undefined) - ]) as Observable - ).pipe( - map(([electionsMembers, councilMembers, technicalCommitteeMembers, societyMembers, sudoKey]): DeriveAccountFlags => { - const isIncluded = address ? isIncludedFn(address) : (): boolean => false; - - return { - isCouncil: (electionsMembers?.map(([id]: ITuple<[AccountId, Balance]>) => id) || councilMembers || []).some(isIncluded), - isSociety: (societyMembers || []).some(isIncluded), - isSudo: sudoKey?.toString() === address?.toString(), - isTechCommittee: (technicalCommitteeMembers || []).some(isIncluded) - }; - }) + return combineLatest([ + address && api.query[councilSection]?.members + ? api.query[councilSection].members() + : of(undefined), + address && api.query.council?.members + ? api.query.council.members() + : of([]), + address && api.query.technicalCommittee?.members + ? api.query.technicalCommittee.members() + : of([]), + address && api.query.society?.members + ? api.query.society.members() + : of([]), + address && api.query.sudo?.key + ? api.query.sudo.key() + : of(undefined) + ]).pipe( + map((result) => parseFlags(address, result)) ); }); } diff --git a/packages/api-derive/src/accounts/info.ts b/packages/api-derive/src/accounts/info.ts index 5f8af624ce..815b2cf257 100644 --- a/packages/api-derive/src/accounts/info.ts +++ b/packages/api-derive/src/accounts/info.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import { ApiInterfaceRx } from '@polkadot/api/types'; -import { AccountId, AccountIndex, Address, Balance, Registration } from '@polkadot/types/interfaces'; +import { AccountId, AccountIndex, Address, Balance, IdentityInfoAdditional, Registration } from '@polkadot/types/interfaces'; import { ITuple } from '@polkadot/types/types'; import { DeriveAccountInfo, DeriveAccountRegistration } from '../types'; @@ -13,6 +13,8 @@ import { u8aToString } from '@polkadot/util'; import { memo } from '../util'; +const UNDEF_HEX = { toHex: () => undefined }; + function dataAsString (data: Data): string | undefined { return data.isRaw ? u8aToString(data.asRaw.toU8a(true)) @@ -35,6 +37,19 @@ function retrieveNick (api: ApiInterfaceRx, accountId?: AccountId): Observable { + return additional.reduce((other: Record, [_key, _value]): Record => { + const key = dataAsString(_key); + const value = dataAsString(_value); + + if (key && value) { + other[key] = value; + } + + return other; + }, {}); +} + function extractIdentity (identityOfOpt?: Option, superOf?: [AccountId, Data]): DeriveAccountRegistration { if (!identityOfOpt?.isSome) { return { judgements: [] }; @@ -44,32 +59,15 @@ function extractIdentity (identityOfOpt?: Option, superOf?: [Accou const topDisplay = dataAsString(info.display); return { - display: superOf - ? dataAsString(superOf[1]) || topDisplay - : topDisplay, - displayParent: superOf - ? topDisplay - : undefined, + display: (superOf && dataAsString(superOf[1])) || topDisplay, + displayParent: superOf && topDisplay, email: dataAsString(info.email), image: dataAsString(info.image), judgements, legal: dataAsString(info.legal), - other: info.additional.reduce((other: Record, [_key, _value]): Record => { - const key = dataAsString(_key); - const value = dataAsString(_value); - - if (key && value) { - other[key] = value; - } - - return other; - }, {}), - parent: superOf - ? superOf[0] - : undefined, - pgp: info.pgpFingerprint.isSome - ? info.pgpFingerprint.unwrap().toHex() - : undefined, + other: extractOther(info.additional), + parent: superOf && superOf[0], + pgp: info.pgpFingerprint.unwrapOr(UNDEF_HEX).toHex(), riot: dataAsString(info.riot), twitter: dataAsString(info.twitter), web: dataAsString(info.web) diff --git a/packages/api-derive/src/democracy/util.ts b/packages/api-derive/src/democracy/util.ts index d51fc18b54..a0f6a0be93 100644 --- a/packages/api-derive/src/democracy/util.ts +++ b/packages/api-derive/src/democracy/util.ts @@ -92,16 +92,7 @@ function calcVotesPrev (votesFor: DeriveReferendumVote[]): DeriveReferendumVoteS state.votedTotal.iadd(counted); return state; - }, { - allAye: [], - allNay: [], - voteCount: 0, - voteCountAye: 0, - voteCountNay: 0, - votedAye: new BN(0), - votedNay: new BN(0), - votedTotal: new BN(0) - }); + }, { allAye: [], allNay: [], voteCount: 0, voteCountAye: 0, voteCountNay: 0, votedAye: new BN(0), votedNay: new BN(0), votedTotal: new BN(0) }); } function calcVotesCurrent (tally: Tally, votes: DeriveReferendumVote[]): DeriveReferendumVoteState { diff --git a/packages/api/src/checkTypes.manual.ts b/packages/api/src/checkTypes.manual.ts index 086c60f5f1..097f397e38 100644 --- a/packages/api/src/checkTypes.manual.ts +++ b/packages/api/src/checkTypes.manual.ts @@ -70,7 +70,9 @@ async function query (api: ApiPromise, keyring: TestKeyringMap): Promise { ]); console.log(multiRes); +} +async function queryExtra (api: ApiPromise, keyring: TestKeyringMap): Promise { // events destructing await api.query.system.events((records): void => { records.forEach(({ event, phase }): void => { @@ -141,8 +143,7 @@ async function tx (api: ApiPromise, keyring: TestKeyringMap): Promise { // transfer, also allows for BigInt inputs here const transfer = api.tx.balances.transfer(keyring.bob.address, 123456789n); - console.log('transfer as Call', transfer as IMethod); - console.log('transfer as Extrinsic', transfer as IExtrinsic); + console.log('transfer casted', transfer as IMethod, transfer as IExtrinsic); // simple "return the hash" variant console.log('hash:', (await transfer.signAndSend(keyring.alice)).toHex()); @@ -158,9 +159,7 @@ async function tx (api: ApiPromise, keyring: TestKeyringMap): Promise { // just with the callback await api.tx.balances .transfer(keyring.bob.address, 12345) - .signAndSend(keyring.alice, ({ status }: SubmittableResult): void => { - console.log('transfer status:', status.type); - }); + .signAndSend(keyring.alice, ({ status }: SubmittableResult) => console.log(status.type)); // with options and the callback const nonce2 = await api.query.system.accountNonce(keyring.alice.address); @@ -176,9 +175,7 @@ async function tx (api: ApiPromise, keyring: TestKeyringMap): Promise { const second = api.tx.democracy.second(123, 5); // eslint-disable-next-line @typescript-eslint/no-floating-promises - second.signAndSend('123', (result): void => { - console.log(result); - }); + await second.signAndSend('123', (result) => console.log(result)); // it handles enum inputs correctly await api.tx.democracy.proxyVote(123, { Split: { nay: 456, yay: 123 } }).signAndSend(keyring.alice); @@ -193,6 +190,7 @@ async function main (): Promise { consts(api), derive(api), query(api, keyring), + queryExtra(api, keyring), rpc(api), types(api), tx(api, keyring) diff --git a/packages/api/test/util/SingleAccountSigner.ts b/packages/api/test/util/SingleAccountSigner.ts index 2fa97e6544..0d92fc5e19 100644 --- a/packages/api/test/util/SingleAccountSigner.ts +++ b/packages/api/test/util/SingleAccountSigner.ts @@ -5,7 +5,7 @@ import { Signer, SignerResult } from '@polkadot/api/types'; import { KeyringPair } from '@polkadot/keyring/types'; import { Registry, SignerPayloadJSON, SignerPayloadRaw } from '@polkadot/types/types'; -import { hexToU8a, u8aToHex } from '@polkadot/util'; +import { assert, hexToU8a, u8aToHex } from '@polkadot/util'; let id = 0; @@ -23,9 +23,7 @@ export class SingleAccountSigner implements Signer { } public async signPayload (payload: SignerPayloadJSON): Promise { - if (payload.address !== this.#keyringPair.address) { - throw new Error('does not have the keyringPair'); - } + assert(payload.address === this.#keyringPair.address, 'Signer does not have the keyringPair'); return new Promise((resolve): void => { setTimeout((): void => { @@ -40,9 +38,7 @@ export class SingleAccountSigner implements Signer { } public async signRaw ({ address, data }: SignerPayloadRaw): Promise { - if (address !== this.#keyringPair.address) { - throw new Error('does not have the keyringPair'); - } + assert(address === this.#keyringPair.address, 'Signer does not have the keyringPair'); return new Promise((resolve): void => { setTimeout((): void => { diff --git a/packages/rpc-provider/src/mock/index.ts b/packages/rpc-provider/src/mock/index.ts index eedc30a3c5..fcb97ef323 100644 --- a/packages/rpc-provider/src/mock/index.ts +++ b/packages/rpc-provider/src/mock/index.ts @@ -16,7 +16,7 @@ import jsonrpc from '@polkadot/types/interfaces/jsonrpc'; import testKeyring from '@polkadot/keyring/testing'; import rpcHeader from '@polkadot/types/json/Header.004.json'; import rpcSignedBlock from '@polkadot/types/json/SignedBlock.004.immortal.json'; -import { bnToU8a, logger, u8aToHex } from '@polkadot/util'; +import { assert, bnToU8a, logger, u8aToHex } from '@polkadot/util'; import { randomAsU8a } from '@polkadot/util-crypto'; const INTERVAL = 1000; @@ -119,9 +119,7 @@ export default class Mock implements ProviderInterface { // eslint-disable-next-line @typescript-eslint/require-await public async send (method: string, params: any[]): Promise { - if (!this.requests[method]) { - throw new Error(`provider.send: Invalid method '${method}'`); - } + assert(this.requests[method], `provider.send: Invalid method '${method}'`); return this.requests[method](this.db, params); } @@ -130,21 +128,19 @@ export default class Mock implements ProviderInterface { public async subscribe (type: string, method: string, ...params: unknown[]): Promise { l.debug((): any => ['subscribe', method, params]); - if (this.subscriptions[method]) { - const callback = params.pop() as MockStateSubscriptionCallback; - const id = ++this.subscriptionId; + assert(this.subscriptions[method], `provider.subscribe: Invalid method '${method}'`); - this.subscriptions[method].callbacks[id] = callback; - this.subscriptionMap[id] = method; + const callback = params.pop() as MockStateSubscriptionCallback; + const id = ++this.subscriptionId; - if (this.subscriptions[method].lastValue !== null) { - callback(null, this.subscriptions[method].lastValue); - } + this.subscriptions[method].callbacks[id] = callback; + this.subscriptionMap[id] = method; - return id; + if (this.subscriptions[method].lastValue !== null) { + callback(null, this.subscriptions[method].lastValue); } - throw new Error(`provider.subscribe: Invalid method '${method}'`); + return id; } // eslint-disable-next-line @typescript-eslint/require-await @@ -153,9 +149,7 @@ export default class Mock implements ProviderInterface { l.debug((): any => ['unsubscribe', id, sub]); - if (!sub) { - throw new Error(`Unable to find subscription for ${id}`); - } + assert(sub, `Unable to find subscription for ${id}`); delete this.subscriptionMap[id]; delete this.subscriptions[sub].callbacks[id]; @@ -236,7 +230,7 @@ export default class Mock implements ProviderInterface { try { cb(null, value.toJSON()); } catch (error) { - console.error(`Error on '${method}' subscription`, error); + l.error(`Error on '${method}' subscription`, error); } }); } diff --git a/packages/types/src/codec/Option.ts b/packages/types/src/codec/Option.ts index d3534abe54..bfac1e87eb 100644 --- a/packages/types/src/codec/Option.ts +++ b/packages/types/src/codec/Option.ts @@ -4,7 +4,7 @@ import { H256 } from '@polkadot/types/interfaces'; import { AnyJson, Codec, Constructor, InterfaceTypes, Registry } from '../types'; -import { isNull, isU8a, isUndefined, u8aToHex } from '@polkadot/util'; +import { assert, isNull, isU8a, isUndefined, u8aToHex } from '@polkadot/util'; import Null from '../primitive/Null'; import { typeToConstructor } from './utils'; @@ -188,9 +188,7 @@ export default class Option implements Codec { * @description Returns the value that the Option represents (if available), throws if null */ public unwrap (): T { - if (this.isNone) { - throw new Error('Option: unwrapping a None value'); - } + assert(this.isSome, 'Option: unwrapping a None value'); return this.#raw; } diff --git a/packages/types/src/codec/Tuple.ts b/packages/types/src/codec/Tuple.ts index 7bd2c0091e..17652701a3 100644 --- a/packages/types/src/codec/Tuple.ts +++ b/packages/types/src/codec/Tuple.ts @@ -3,7 +3,7 @@ import { AnyNumber, AnyU8a, AnyString, Codec, Constructor, InterfaceTypes, Registry } from '../types'; -import { isU8a, u8aConcat, isHex, hexToU8a } from '@polkadot/util'; +import { isU8a, isHex, hexToU8a, u8aConcat } from '@polkadot/util'; import { decodeU8a, mapToTypeMap, typeToConstructor } from './utils'; import AbstractArray from './AbstractArray'; diff --git a/packages/types/src/create/createClass.ts b/packages/types/src/create/createClass.ts index f1ce3552bc..2286745d8c 100644 --- a/packages/types/src/create/createClass.ts +++ b/packages/types/src/create/createClass.ts @@ -187,9 +187,7 @@ export function getTypeClass (registry: Registry, value const getFn = infoMapping[value.info]; - if (!getFn) { - throw new Error(`Unable to construct class from ${JSON.stringify(value)}`); - } + assert(getFn, `Unable to construct class from ${JSON.stringify(value)}`); return getFn(registry, value) as Constructor; } diff --git a/packages/types/src/create/registry.ts b/packages/types/src/create/registry.ts index aabfd0ddc4..7ef4965bc9 100644 --- a/packages/types/src/create/registry.ts +++ b/packages/types/src/create/registry.ts @@ -274,9 +274,7 @@ export class TypeRegistry implements Registry { public getOrThrow (name: string, msg?: string): Constructor { const Type = this.get(name); - if (isUndefined(Type)) { - throw new Error(msg || `type ${name} not found`); - } + assert(!isUndefined(Type), msg || `type ${name} not found`); return Type; } diff --git a/packages/types/src/ethereum/LookupSource.ts b/packages/types/src/ethereum/LookupSource.ts index 80e54e5121..93c176f870 100644 --- a/packages/types/src/ethereum/LookupSource.ts +++ b/packages/types/src/ethereum/LookupSource.ts @@ -4,7 +4,7 @@ import { Registry } from '../types'; import BN from 'bn.js'; -import { isBn, isHex, isNumber, isU8a, u8aConcat, u8aToHex, u8aToU8a, u8aToBn } from '@polkadot/util'; +import { isBigInt, isBn, isHex, isNumber, isU8a, u8aConcat, u8aToHex, u8aToU8a, u8aToBn } from '@polkadot/util'; import { decodeAddress } from '@polkadot/util-crypto'; import Base from '../codec/Base'; @@ -12,7 +12,7 @@ import AccountIndex from '../generic/AccountIndex'; import EthereumAccountId from './AccountId'; // eslint-disable-next-line no-use-before-define -type AnyAddress = BN | LookupSource | EthereumAccountId | AccountIndex | number[] | Uint8Array | number | string; +type AnyAddress = BigInt | BN | LookupSource | EthereumAccountId | AccountIndex | number[] | Uint8Array | number | string; export const ACCOUNT_ID_PREFIX = new Uint8Array([0xff]); @@ -55,17 +55,15 @@ export default class LookupSource extends Base /** @internal */ private static _decodeAddress (registry: Registry, value: AnyAddress): EthereumAccountId | AccountIndex { - if (value instanceof EthereumAccountId || value instanceof AccountIndex) { - return value; - } else if (value instanceof LookupSource) { - return value._raw; - } else if (isBn(value) || isNumber(value)) { - return registry.createType('AccountIndex', value); - } else if (Array.isArray(value) || isHex(value) || isU8a(value)) { - return decodeU8a(registry, u8aToU8a(value)); - } - - return decodeString(registry, value); + return value instanceof LookupSource + ? value._raw + : value instanceof EthereumAccountId || value instanceof AccountIndex + ? value + : isBn(value) || isNumber(value) || isBigInt(value) + ? registry.createType('AccountIndex', value) + : Array.isArray(value) || isHex(value) || isU8a(value) + ? decodeU8a(registry, u8aToU8a(value)) + : decodeString(registry, value); } /** diff --git a/packages/types/src/extrinsic/ExtrinsicEra.ts b/packages/types/src/extrinsic/ExtrinsicEra.ts index 32dbd0082c..afd948387f 100644 --- a/packages/types/src/extrinsic/ExtrinsicEra.ts +++ b/packages/types/src/extrinsic/ExtrinsicEra.ts @@ -4,7 +4,7 @@ import { AnyU8a, IExtrinsicEra, Registry } from '../types'; import BN from 'bn.js'; -import { assert, bnToBn, formatNumber, hexToU8a, isHex, isU8a, isObject, u8aToBn } from '@polkadot/util'; +import { assert, bnToBn, formatNumber, hexToU8a, isHex, isU8a, isObject, u8aToBn, u8aToU8a } from '@polkadot/util'; import Enum from '../codec/Enum'; import Tuple from '../codec/Tuple'; @@ -67,12 +67,8 @@ export class MortalEra extends Tuple { /** @internal */ private static _decodeMortalEra (registry: Registry, value?: MortalMethod | Uint8Array | number[] | string): MortalEraValue { - if (isHex(value)) { - return MortalEra._decodeMortalU8a(registry, hexToU8a(value)); - } else if (Array.isArray(value)) { - return MortalEra._decodeMortalU8a(registry, new Uint8Array(value)); - } else if (isU8a(value)) { - return MortalEra._decodeMortalU8a(registry, value); + if (isU8a(value) || isHex(value) || Array.isArray(value)) { + return MortalEra._decodeMortalU8a(registry, u8aToU8a(value)); } else if (isObject(value)) { return MortalEra._decodeMortalObject(registry, value); } else if (!value) { diff --git a/packages/types/src/generic/LookupSource.ts b/packages/types/src/generic/LookupSource.ts index b11b991cb9..da44ae6f5b 100644 --- a/packages/types/src/generic/LookupSource.ts +++ b/packages/types/src/generic/LookupSource.ts @@ -4,7 +4,7 @@ import { Registry } from '../types'; import BN from 'bn.js'; -import { isBn, isHex, isNumber, isU8a, u8aConcat, u8aToHex, u8aToU8a, u8aToBn } from '@polkadot/util'; +import { isBigInt, isBn, isHex, isNumber, isU8a, u8aConcat, u8aToHex, u8aToU8a, u8aToBn } from '@polkadot/util'; import { decodeAddress } from '@polkadot/util-crypto'; import Base from '../codec/Base'; @@ -12,7 +12,7 @@ import AccountId from './AccountId'; import AccountIndex from './AccountIndex'; // eslint-disable-next-line no-use-before-define -type AnyAddress = BN | LookupSource | AccountId | AccountIndex | number[] | Uint8Array | number | string; +type AnyAddress = BigInt | BN | LookupSource | AccountId | AccountIndex | number[] | Uint8Array | number | string; export const ACCOUNT_ID_PREFIX = new Uint8Array([0xff]); @@ -55,17 +55,15 @@ export default class LookupSource extends Base { /** @internal */ private static _decodeAddress (registry: Registry, value: AnyAddress): AccountId | AccountIndex { - if (value instanceof AccountId || value instanceof AccountIndex) { - return value; - } else if (value instanceof LookupSource) { - return value._raw; - } else if (isBn(value) || isNumber(value)) { - return registry.createType('AccountIndex', value); - } else if (Array.isArray(value) || isHex(value) || isU8a(value)) { - return decodeU8a(registry, u8aToU8a(value)); - } - - return decodeString(registry, value); + return value instanceof LookupSource + ? value._raw + : value instanceof AccountId || value instanceof AccountIndex + ? value + : isBn(value) || isNumber(value) || isBigInt(value) + ? registry.createType('AccountIndex', value) + : Array.isArray(value) || isHex(value) || isU8a(value) + ? decodeU8a(registry, u8aToU8a(value)) + : decodeString(registry, value); } /** diff --git a/packages/types/src/primitive/Data.ts b/packages/types/src/primitive/Data.ts index a2e88bd8e4..639a26e79e 100644 --- a/packages/types/src/primitive/Data.ts +++ b/packages/types/src/primitive/Data.ts @@ -10,7 +10,7 @@ import Enum from '../codec/Enum'; import Bytes from './Bytes'; /** @internal */ -function decodeDataU8a (registry: Registry, value: Uint8Array): [any, number | undefined] { +function decodeDataU8a (registry: Registry, value: Uint8Array): [undefined | null | Uint8Array, number | undefined] { if (!value.length) { return [undefined, undefined]; } diff --git a/packages/types/src/primitive/DoNotConstruct.ts b/packages/types/src/primitive/DoNotConstruct.ts index 8b2a6443c6..5b118a9806 100644 --- a/packages/types/src/primitive/DoNotConstruct.ts +++ b/packages/types/src/primitive/DoNotConstruct.ts @@ -11,13 +11,13 @@ import Null from './Null'; * An unknown type that fails on construction with the type info */ export default class DoNotConstruct extends Null { - constructor (registry: Registry, typeName: string) { + constructor (registry: Registry, typeName = 'DoNotConstruct') { super(registry); throw new Error(`Cannot construct unknown type ${typeName}`); } - public static with (typeName = 'DoNotConstruct'): Constructor { + public static with (typeName?: string): Constructor { return class extends DoNotConstruct { constructor (registry: Registry) { super(registry, typeName);