fix(structures): correctly check if flags are present (#11404)

* fix(structures): correctly check if flags are present

* chore: isFieldSet type guard

---------

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
This commit is contained in:
Qjuh
2026-01-27 17:47:56 +01:00
committed by GitHub
parent 323d8e7571
commit 7a7fecbe3c
4 changed files with 41 additions and 9 deletions

View File

@@ -3,7 +3,7 @@ import type { APIChannel, APIPartialChannel, ChannelType, ChannelFlags } from 'd
import { Structure } from '../Structure.js';
import { ChannelFlagsBitField } from '../bitfields/ChannelFlagsBitField.js';
import { kData } from '../utils/symbols.js';
import { isIdSet } from '../utils/type-guards.js';
import { isFieldSet, isIdSet } from '../utils/type-guards.js';
import type { Partialize } from '../utils/types.js';
import type { ChannelPermissionMixin } from './mixins/ChannelPermissionMixin.js';
import type { ChannelWebhookMixin } from './mixins/ChannelWebhookMixin.js';
@@ -82,9 +82,9 @@ export class Channel<
* to null, respecting Omit behaviors
*/
public get flags() {
const flags =
'flags' in this[kData] && typeof this[kData].flags === 'number' ? (this[kData].flags as ChannelFlags) : null;
return flags ? new ChannelFlagsBitField(flags) : null;
return isFieldSet(this[kData], 'flags', 'number')
? new ChannelFlagsBitField(this[kData].flags as ChannelFlags)
: null;
}
/**

View File

@@ -2,6 +2,7 @@ import type { APIAttachment, AttachmentFlags } from 'discord-api-types/v10';
import { Structure } from '../Structure.js';
import { AttachmentFlagsBitField } from '../bitfields/AttachmentFlagsBitField.js';
import { kData } from '../utils/symbols.js';
import { isFieldSet } from '../utils/type-guards.js';
import type { Partialize } from '../utils/types.js';
export class Attachment<Omitted extends keyof APIAttachment | '' = ''> extends Structure<APIAttachment, Omitted> {
@@ -112,7 +113,8 @@ export class Attachment<Omitted extends keyof APIAttachment | '' = ''> extends S
* Attachment flags combined as a bitfield
*/
public get flags() {
const flags = this[kData].flags;
return flags ? new AttachmentFlagsBitField(this[kData].flags as AttachmentFlags) : null;
return isFieldSet(this[kData], 'flags', 'number')
? new AttachmentFlagsBitField(this[kData].flags as AttachmentFlags)
: null;
}
}

View File

@@ -4,7 +4,7 @@ import { Structure } from '../Structure.js';
import { MessageFlagsBitField } from '../bitfields/MessageFlagsBitField.js';
import { dateToDiscordISOTimestamp } from '../utils/optimization.js';
import { kData, kEditedTimestamp } from '../utils/symbols.js';
import { isIdSet } from '../utils/type-guards.js';
import { isFieldSet, isIdSet } from '../utils/type-guards.js';
import type { Partialize } from '../utils/types.js';
// TODO: missing substructures: application
@@ -110,8 +110,9 @@ export class Message<Omitted extends keyof APIMessage | '' = 'edited_timestamp'
* The flags of this message as a bit field
*/
public get flags() {
const flags = this[kData].flags;
return flags ? new MessageFlagsBitField(this[kData].flags as MessageFlags) : null;
return isFieldSet(this[kData], 'flags', 'number')
? new MessageFlagsBitField(this[kData].flags as MessageFlags)
: null;
}
/**

View File

@@ -1,3 +1,32 @@
export function isIdSet(id: unknown): id is bigint | string {
return typeof id === 'string' || typeof id === 'bigint';
}
interface TypeMap {
bigint: bigint;
boolean: boolean;
function(...args: any[]): unknown;
number: number;
object: object;
string: string;
symbol: symbol;
undefined: undefined;
}
export type TypeofType = keyof TypeMap;
function hasProperty<Value extends object, Key extends string>(
data: Value,
fieldName: Key,
): data is Record<Key, unknown> & Value {
return fieldName in data;
}
export function isFieldSet<Value extends object, Key extends string, Type extends TypeofType>(
data: Value,
fieldName: Key,
type: Type,
): data is Record<Key, TypeMap[Type]> & Value {
// eslint-disable-next-line valid-typeof
return hasProperty(data, fieldName) && typeof data[fieldName] === type;
}