diff --git a/packages/transaction-messages/src/__typetests__/instructions-typetest.ts b/packages/transaction-messages/src/__typetests__/instructions-typetest.ts index 340ffff49..e349512fa 100644 --- a/packages/transaction-messages/src/__typetests__/instructions-typetest.ts +++ b/packages/transaction-messages/src/__typetests__/instructions-typetest.ts @@ -15,7 +15,7 @@ import { prependTransactionMessageInstruction, prependTransactionMessageInstructions, } from '../instructions'; -import { BaseTransactionMessage } from '../transaction-message'; +import { BaseTransactionMessage, TransactionMessage } from '../transaction-message'; import { TransactionMessageWithinSizeLimit } from '../transaction-message-size'; type Instruction = BaseTransactionMessage['instructions'][number]; @@ -23,6 +23,8 @@ type InstructionA = Instruction & { identifier: 'A' }; type InstructionB = Instruction & { identifier: 'B' }; type InstructionC = Instruction & { identifier: 'C' }; +type TransactionMessageNotLegacy = Exclude; + // [DESCRIBE] appendTransactionMessageInstruction { // It returns the same TransactionMessage type @@ -91,6 +93,17 @@ type InstructionC = Instruction & { identifier: 'C' }; // @ts-expect-error Potentially no longer within size limit. newMessage satisfies TransactionMessageWithinSizeLimit; } + + // It can narrow the version type + { + const message = null as unknown as TransactionMessage; + const newMessage = appendTransactionMessageInstruction(null as unknown as Instruction, message); + // @ts-expect-error Could be legacy + newMessage satisfies TransactionMessageNotLegacy; + if (newMessage.version === 0) { + newMessage satisfies TransactionMessageNotLegacy; + } + } } // [DESCRIBE] appendTransactionMessageInstructions @@ -133,6 +146,17 @@ type InstructionC = Instruction & { identifier: 'C' }; // @ts-expect-error Potentially no longer within size limit. newMessage satisfies TransactionMessageWithinSizeLimit; } + + // It can narrow the version type + { + const message = null as unknown as TransactionMessage; + const newMessage = appendTransactionMessageInstructions([null as unknown as Instruction], message); + // @ts-expect-error Could be legacy + newMessage satisfies TransactionMessageNotLegacy; + if (newMessage.version === 0) { + newMessage satisfies TransactionMessageNotLegacy; + } + } } // [DESCRIBE] prependTransactionMessageInstruction @@ -221,6 +245,17 @@ type InstructionC = Instruction & { identifier: 'C' }; // @ts-expect-error Potentially no longer within size limit. newMessage satisfies TransactionMessageWithinSizeLimit; } + + // It can narrow the version type + { + const message = null as unknown as TransactionMessage; + const newMessage = prependTransactionMessageInstruction(null as unknown as Instruction, message); + // @ts-expect-error Could be legacy + newMessage satisfies TransactionMessageNotLegacy; + if (newMessage.version === 0) { + newMessage satisfies TransactionMessageNotLegacy; + } + } } // [DESCRIBE] prependTransactionMessageInstructions @@ -273,4 +308,15 @@ type InstructionC = Instruction & { identifier: 'C' }; // @ts-expect-error Potentially no longer within size limit. newMessage satisfies TransactionMessageWithinSizeLimit; } + + // It can narrow the version type + { + const message = null as unknown as TransactionMessage; + const newMessage = prependTransactionMessageInstructions([null as unknown as Instruction], message); + // @ts-expect-error Could be legacy + newMessage satisfies TransactionMessageNotLegacy; + if (newMessage.version === 0) { + newMessage satisfies TransactionMessageNotLegacy; + } + } } diff --git a/packages/transaction-messages/src/instructions.ts b/packages/transaction-messages/src/instructions.ts index 48f290620..cef9763ac 100644 --- a/packages/transaction-messages/src/instructions.ts +++ b/packages/transaction-messages/src/instructions.ts @@ -1,7 +1,7 @@ import { Instruction } from '@solana/instructions'; import { ExcludeTransactionMessageDurableNonceLifetime } from './durable-nonce'; -import { BaseTransactionMessage } from './transaction-message'; +import { TransactionMessage } from './transaction-message'; import { ExcludeTransactionMessageWithinSizeLimit } from './transaction-message-size'; /** @@ -9,25 +9,29 @@ import { ExcludeTransactionMessageWithinSizeLimit } from './transaction-message- * without losing type information about the current instructions. */ type AppendTransactionMessageInstructions< - TTransactionMessage extends BaseTransactionMessage, + TTransactionMessage extends TransactionMessage, TInstructions extends readonly Instruction[], -> = Omit, 'instructions'> & { - readonly instructions: readonly [...TTransactionMessage['instructions'], ...TInstructions]; -}; +> = TTransactionMessage extends TransactionMessage + ? Omit, 'instructions'> & { + readonly instructions: readonly [...TTransactionMessage['instructions'], ...TInstructions]; + } + : never; /** * A helper type to prepend instructions to a transaction message * without losing type information about the current instructions. */ type PrependTransactionMessageInstructions< - TTransactionMessage extends BaseTransactionMessage, + TTransactionMessage extends TransactionMessage, TInstructions extends readonly Instruction[], -> = Omit< - ExcludeTransactionMessageWithinSizeLimit>, - 'instructions' -> & { - readonly instructions: readonly [...TInstructions, ...TTransactionMessage['instructions']]; -}; +> = TTransactionMessage extends TransactionMessage + ? Omit< + ExcludeTransactionMessageWithinSizeLimit>, + 'instructions' + > & { + readonly instructions: readonly [...TInstructions, ...TTransactionMessage['instructions']]; + } + : never; /** * Given an instruction, this method will return a new transaction message with that instruction @@ -52,7 +56,7 @@ type PrependTransactionMessageInstructions< * ``` */ export function appendTransactionMessageInstruction< - TTransactionMessage extends BaseTransactionMessage, + TTransactionMessage extends TransactionMessage, TInstruction extends Instruction, >( instruction: TInstruction, @@ -89,7 +93,7 @@ export function appendTransactionMessageInstruction< * ``` */ export function appendTransactionMessageInstructions< - TTransactionMessage extends BaseTransactionMessage, + TTransactionMessage extends TransactionMessage, const TInstructions extends readonly Instruction[], >( instructions: TInstructions, @@ -101,7 +105,7 @@ export function appendTransactionMessageInstructions< ...(transactionMessage.instructions as TTransactionMessage['instructions']), ...instructions, ] as readonly [...TTransactionMessage['instructions'], ...TInstructions]), - }); + }) as AppendTransactionMessageInstructions; } /** @@ -126,7 +130,7 @@ export function appendTransactionMessageInstructions< * ``` */ export function prependTransactionMessageInstruction< - TTransactionMessage extends BaseTransactionMessage, + TTransactionMessage extends TransactionMessage, TInstruction extends Instruction, >( instruction: TInstruction, @@ -163,7 +167,7 @@ export function prependTransactionMessageInstruction< * ``` */ export function prependTransactionMessageInstructions< - TTransactionMessage extends BaseTransactionMessage, + TTransactionMessage extends TransactionMessage, const TInstructions extends readonly Instruction[], >( instructions: TInstructions, @@ -175,5 +179,5 @@ export function prependTransactionMessageInstructions< ...instructions, ...(transactionMessage.instructions as TTransactionMessage['instructions']), ] as readonly [...TInstructions, ...TTransactionMessage['instructions']]), - }); + }) as unknown as PrependTransactionMessageInstructions; }